天天看点

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则是在可以获取到环境里面的值,在进行过滤判断,如获取当前运行环境或者系统,进行过滤。