天天看點

Spring源碼從入門到精通---@Profile(十五)

上篇文章主要說了Aware接口:

如何吧spring底層元件指派到自定義元件裡呢,可以實作xxxAware接口,比如實作ApplicationContextAware接口,可以擷取到applicationContext。這些都是由xxxAwareProcessor後置處理器處理的,如ApplicationContextAwareProcessor,先建立bean之後,後置處理器處理吧對應的資料指派。

Aware&原理---Spring源碼從入門到精通(十四)

這篇文章主要說@Profile:

文章分為兩個部分,第一部分,資料源環境的搭建。第二部分,@Profile能根據開發環境和測試環境,加在不同的資料源,是以第二部分,如何通過spring提供的@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的自行百度。

Spring源碼從入門到精通---@Profile(十五)

二、@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的就列印不出來。

Spring源碼從入門到精通---@Profile(十五)

問:@Confitional注解和@Profile注解都能用在類上,并且都是不滿足就不加載,有什麼不同?

@Profile是修改系統環境的資料,需要在ioc容器refresh()之前設定,是以不能用有參構造加載配置類。

@Conditional則是在可以擷取到環境裡面的值,在進行過濾判斷,如擷取目前運作環境或者系統,進行過濾。