1.profiles
(1) profiles提供了一種在不同環境(Environment)下注冊不同的bean的機制,如下
//假定現在我們存在開發和生產兩個環境,每種環境下ExampleA所需的url都是不同的,那么我們就可以使用@Profile注解,來宣告在哪種環境下該注入哪種bean
@Configuration
public class Config {
//development環境下注入該bean
@Bean
@Profile("development")
public ExampleA exampleAForDevelopment() {
return new ExampleA("http://127.0.0.1:8080");
}
//production環境下注入該bean
@Bean
@Profile("production")
public ExampleA exampleAForProduction() {
return new ExampleA("http://192.168.7.70:8080");
}
}
@Profile屬性值不僅可以為一個字串值,亦可以為一個運算式,規則如下:
-
! : 邏輯非
-
| : 邏輯或
-
& : 邏輯與
@Configuration
public class Config {
//使用邏輯或,宣告在development或test環境下注入這個bean ExampleA
@Bean
@Profile("development | test")
public ExampleA exampleAForDevelopment() {
return new ExampleA("http://127.0.0.1:8080");
}
//宣告在production環境下且online或offline中至少某一種環境被激活下注入這個bean
@Bean
@Profile("production & (online | offline)")
public ExampleA exampleAForProduction() {
return new ExampleA("http://192.168.7.70:8080");
}
}
//例一:只宣告profile為production,觀察列印結果,可見未有任何ExampleA被注入到容器中
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//使用Environment中的setActiveProfiles方法來設定激活哪一個profile
ctx.getEnvironment().setActiveProfiles("production");
ctx.register(Config.class);
ctx.refresh();
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
//例二:指定多個配置資訊,觀察列印結果,可見兩個ExampleA都被注入到容器中
//setActiveProfiles方法可同時激活多個profile
ctx.getEnvironment().setActiveProfiles("production", "online", "test");
(2) @Profile注解可用作元注解,用于創建自定義組合注解
//下面這個@Production注解,等價于@Profile("production")注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @interface Production {
}
(3) 對于多載的@Bean方法,@Profile會先校驗其中的第一個方法,如果它不通過,則后面所有它的多載方法也全部不通過,否則,在上一個多載方法通過后,它才會繼續接下來的剩余多載方法的校驗,例子如下
//該Config類中有兩個多載方法exampleA,它們的profile屬性值不相同
@Configuration
public class Config {
@Bean
@Profile("dev")
public ExampleA exampleA(@Value("aaa") String str) {
return new ExampleA();
}
@Bean
@Profile("prod")
public ExampleA exampleA() {
return new ExampleA();
}
}
//先設定active-profile為prod,如下,啟動容器,會發現容器拋出NoSuchBeanDefinitionException例外,這就是因為容器先校驗了exampleA(String str)這個方法,發現它的profile為dev,不符,因此,后面的它的多載方法exampleA()也直接不通過,故而沒有一個ExampleA實體被裝入到容器中
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("prod");
ctx.register(Config.class);
ctx.refresh();
System.out.println(ctx.getBean(ExampleA.class));
//對于上面的例子,我們只顛倒Config類中兩個方法的位置,如下
@Configuration
public class Config {
@Bean
@Profile("prod")
public ExampleA exampleA() {
return new ExampleA();
}
@Bean
@Profile("dev")
public ExampleA exampleA(@Value("aaa") String str) {
return new ExampleA();
}
}
//然后,再次啟動容器,會發現我們獲得了一個ExampleA實體,這就是因為容器先校驗了exampleA(),其profile值與active-profile值一致,通過,接下來校驗exampleA(String str),結果不通過,因此會有一個ExampleA實體被注入到容器中
(4) 在基于xml的配置中,我們可以指定<beans/>標簽中profile屬性的值,來進行配置,如下
<!-- 相當于在@Configuration類上添加了@Profile("prod")注解 -->
<beans profile="prod" ....>
<!-- bean的定義... -->
</beans>
<!-- 在xml的配置中,profile的屬性值不能使用像注解那樣的運算式,比如前面的運算式:production & (online | offline) 是不能用于xml中的,不過xml支持 ! 運算子 -->
<beans profile="!prod" ....>
<!-- bean的定義... -->
</beans>
<!-- 雖然xml中不支持運算式,但為了表達出 &(與) 的效果,我們可以這樣宣告 -->
<beans ...>
<!-- 等價于@Profile("prod & online") -->
<beans profile="prod">
<beans profile="online">
<!-- bean的定義... -->
</beans>
</beans>
</beans>
(5) 在前面的例子中,我們已經看到了,可通過Environment中的setActiveProfiles()方法來選擇激活某一個或多個profile,除此之外,我們還可以通過配置spring.profiles.active的屬性值來宣告激活哪些profile,這個spring.profiles.active可在springboot專案中的yml組態檔中進行配置,或通過jvm系統引數來進行配置,如下
(6) profile的默認屬性值為default,可通過Environment中的setDefaultProfiles()方法或指定spring.profiles.default的屬性值來進行修改
//@Profile("default")代表啟用默認配置,即如果當前Environment中沒有任何profile被指定,那么這個bean就會被添加到容器中,反之,如果指定了任何profile,那么這個bean就會被排除在外
@Configuration
@Profile("default")
public class Config {
@Bean
public ExampleA exampleA() {
return new ExampleA();
}
}
2.PropertySource概要
未完待續...
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545277.html
標籤:Java
上一篇:Spring 原始碼環境搭建
下一篇:自定義例外
