上篇文章主要說了Aware接口:
如何吧spring底層元件指派到自定義元件裡呢,可以實作xxxAware接口,比如實作ApplicationContextAware接口,可以擷取到applicationContext。這些都是由xxxAwareProcessor後置處理器處理的,如ApplicationContextAwareProcessor,先建立bean之後,後置處理器處理吧對應的資料指派。
Aware&原理---Spring源碼從入門到精通(十四)
這篇文章主要說@Profile:
文章分為兩個部分,第一部分,資料源環境的搭建。第二部分,@Profile能根據開發環境和測試環境,加在不同的資料源,是以第二部分,如何通過spring提供的@Profile注解,根據我們目前的開發環境,動态的激活和切換一系列元件。
一、資料源環境搭建
先貼一份本文目錄
首先建立myConfigProfile類,建立dataSource.properties配置檔案,用我們之前學到過的@PropertySource注解指定加載的配置檔案,用三種不同的方法擷取到配置檔案裡面的值,都是我們之前學到過得。
1)、@Value普通擷取值
2)、在方法參數上用@Value擷取值
3)、實作EmbeddedValueResolverAware接口,解析器擷取運作環境裡面的值。
配置檔案如下:
dataName=root
dataPassword=root
data.driver.class=com.mysql.jdbc.Driver
複制
新的配置類如下:
/**
* @Profile:根據我們的目前環境,動态的激活和切換一系列元件。
* 如test環境用test配置,dev環境用dev配置
*
* @author keying
*/
@PropertySource(value = {"classpath:/dataSources.properties"})
@Configuration
public class MyConfigProfile implements EmbeddedValueResolverAware {
@Value("${dataName}")
private String user;
private String driverClass;
@Bean("testDataSource")
public DataSource test(@Value("${dataPassword}") String password) throws Exception {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/testmac");
comboPooledDataSource.setDriverClass(driverClass);
return comboPooledDataSource;
}
@Bean("devDataSource")
public DataSource dev(@Value("${dataPassword}") String password) throws Exception {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/dev");
comboPooledDataSource.setDriverClass(driverClass);
return comboPooledDataSource;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
//配置檔案資訊放入環境裡,解析器從環境資訊中擷取
this.driverClass = resolver.resolveStringValue("${data.driver.class}");
}
}
複制
/**
* @author keying
*/
public class IOCTestProfile {
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
MyConfigProfile.class);
//根據類型擷取資料源
String[] strings = applicationContext.getBeanNamesForType(DataSource.class);
for(String string:strings){
System.out.println(string);
}
}
}
複制
通過junitTest列印可以看到,可以擷取我們的兩個資料源。本文示範是連結mysql資料庫兩個不同的database,同學請先在電腦上安裝mysql資料庫并建立好test和dev兩個資料庫,不知道安裝mysql的自行百度。
二、@Profile注解使用
1、預設會加載@Profile("default"),指定元件在哪個環境才會注冊到容器中,否則都不會注冊到IOC容器。
2、改為加載test資料源:
* 1)使用指令行參數,在虛拟機參數位子加:-Dspring.profile.active=test
* 2)使用代碼的方式,代碼不能用有參構造器加載,從源碼可以看到,配置類直接加載,就不能改系統環境裡面的值。用無參構造器refresh()容器,其實就是源碼裡的三步,第一步this()無參建立對象,第二部register注冊配置類,第三部重新整理建立容器。
* 3)沒有配置@Profile的bean,不管在哪個環境都能加載。@Profile可以寫在方法上,選擇加載指定環境的配置元件。寫在配置類上,隻有滿足目前環境,整個類才會加載。
/**
* @author keying
*/
public class IOCTestProfile {
/**
* 1、預設會加載@Profile("default"),指定元件在哪個環境才會注冊到容器中,否則都不會注冊到IOC容器。
* 2、改為加載test資料源:
* 1)使用指令行參數,在虛拟機參數位子加:-Dspring.profile.active=test
* 2)使用代碼的方式,代碼不能用有參構造器加載,從源碼可以看到,配置類直接加載,就不能改系統環境裡面的值。
* 用無參構造器refresh()容器,其實就是源碼裡的三步,第一步this()無參建立對象,第二部register注冊配置類,第三部重新整理建立容器。
* 3)沒有配置@Profile的bean,不管在哪個環境都能加載。
*
* @Profile可以寫在方法上,選擇加載指定環境的配置元件。寫在配置類上,隻有滿足目前環境,整個類才會加載。
*/
@Test
public void test() {
//第一步建立applicationContext對象
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
);
//第二部設定需要激活的環境
ConfigurableEnvironment configurableEnvironment = applicationContext.getEnvironment();
configurableEnvironment.setActiveProfiles("test");
//第三部注冊主配置類
applicationContext.register(MyConfigProfile.class);
//第四部重新整理啟動
applicationContext.refresh();
//根據類型擷取資料源
String[] strings = applicationContext.getBeanNamesForType(DataSource.class);
for (String string : strings) {
System.out.println(string);
}
Yellow yellow = applicationContext.getBean(Yellow.class);
System.out.println(yellow);
applicationContext.close();
}
}
複制
/**
* @author keying
* @Profile:根據我們的目前環境,動态的激活和切換一系列元件。如test環境用test配置,dev環境用dev配置
*/
@PropertySource(value = {"classpath:/dataSources.properties"})
@Configuration
//@Profile("test")
public class MyConfigProfile implements EmbeddedValueResolverAware {
@Value("${dataName}")
private String user;
private String driverClass;
@Bean
public Yellow yellow(){
return new Yellow();
}
@Profile("test")
@Bean("testDataSource")
public DataSource test(@Value("${dataPassword}") String password) throws Exception {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/testmac");
comboPooledDataSource.setDriverClass(driverClass);
return comboPooledDataSource;
}
@Profile("dev")
@Bean("devDataSource")
public DataSource dev(@Value("${dataPassword}") String password) throws Exception {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/dev");
comboPooledDataSource.setDriverClass(driverClass);
return comboPooledDataSource;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
//配置檔案資訊放入環境裡,解析器從環境資訊中擷取
this.driverClass = resolver.resolveStringValue("${data.driver.class}");
}
}
複制
從列印可以看出來,yellow在設定了test環境之後,還是 能列印出來,并且profile注解配置了dev的就列印不出來。
問:@Confitional注解和@Profile注解都能用在類上,并且都是不滿足就不加載,有什麼不同?
@Profile是修改系統環境的資料,需要在ioc容器refresh()之前設定,是以不能用有參構造加載配置類。
@Conditional則是在可以擷取到環境裡面的值,在進行過濾判斷,如擷取目前運作環境或者系統,進行過濾。