Spring 源碼環境搭建 Spring 是面向 Bean 的編程,Bean 在其中起到了巨大的作用,而 Spring 提供了 IOC 容器來管理對象之間的依賴關係,使我們可以更加關註業務,輕鬆的構建一個企業應用。藉助 IOC 特性和 AOP 面向切麵編程,可以說 Spring 為開發者提供了無限的 ...
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概要
未完待續...