上篇文章主要说了Aware接口:
如何吧spring底层组件赋值到自定义组件里呢,可以实现xxxAware接口,比如实现ApplicationContextAware接口,可以获取到applicationContext。这些都是由xxxAwareProcessor后置处理器处理的,如ApplicationContextAwareProcessor,先创建bean之后,后置处理器处理吧对应的数据赋值。
这篇文章主要说@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则是在可以获取到环境里面的值,在进行过滤判断,如获取当前运行环境或者系统,进行过滤。