Spring注解——@Profile详解

一、Spring中的Profile

Spring中的Profile功能可以理解为我们在Spring容器中所定义的Bean的逻辑组名称,只有当这些Profile被激活的时候,才会将Profile中所对应的Bean注册到Spring IoC容器中。

举个更具体的例子,我们以前所定义的Bean,当Spring容器一启动的时候,就会一股脑的全部加载我们自定义配置的信息和完成对Bean的创建;而使用了Profile之后,它会将Bean的定义进行更细粒度的划分,将这些定义的Bean划分为几个不同的组,当Spring容器加载配置信息的时候,首先查找激活的Profile,然后只会去加载被激活的组中所定义的Bean信息,而不被激活的Profile中所定义的Bean定义信息是不会被加载,也就不会创建这些Bean。

二、为什么要使用Profile

由于我们平时在开发中,通常会出现在开发的时候使用一个开发用的数据库,测试的时候使用一个测试的数据库,而实际部署的时候需要一个数据库。而使用了Profile之后,我们就可以分别定义3个配置文件,一个用于开发、一个用于测试、一个用于生产,其分别对应于3个Profile。当在实际运行的时候,只需给定一个参数来激活对应的Profile即可,那么容器就会只加载激活后的配置文件,这样就可以大大省去我们修改配置信息而带来的烦恼。

三、配置Profile示例

下面通过以数据源配置为例,在配置环境中使用@Profile注解来管理Bean的装配。

1.创建一个Maven项目,并且引入以下依赖:

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-context</artifactId>
		    <version>4.3.26.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/junit/junit -->
		<dependency>
		  <groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>	
		<!-- c3p0依赖包 -->
		<dependency>
		    <groupId>c3p0</groupId>
		    <artifactId>c3p0</artifactId>
		    <version>0.9.1.2</version>
		</dependency>
  </dependencies>

2.创建一个配置文件dbconfig.properties,其中添加访问数据库所需的基本信息。

db.user=root
db.password=123
db.driverClass=com.mysql.jdbc.Driver

3.创建一个配置类SpringConfigOfProfile,其中配置三个数据源,并用@Profile注解来进行标识。

@Configuration
public class SpringConfigOfProfile implements EmbeddedValueResolverAware {

	@Value("${db.user}")
	private String user;// 用户名
	@Value("${db.password}")
	private String password;// 密码

	private StringValueResolver stringValueResolver;

	private String driverClass;// 数据库驱动

	@Bean
	Person Person() {// 没被@Profile注解标识则在任何环境都加载
		return new Person();
	}

	@Profile("test") // 测试环境标识
	@Bean("dataSourceOfTest")
	public DataSource dataSourceOfTest() {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		// 配置数据库连接池ComboPooledDataSource
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
		return dataSource;
	}

	@Profile("development") // 开发环境标识
	@Bean("dataSourceOfDev")
	public DataSource dataSourceOfDev() {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/A");
		return dataSource;
	}

	@Profile("production") // 生产环境标识
	@Bean("dataSourceOfPro")
	public DataSource dataSourceOfPro() {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/production");
		return dataSource;
	}

	/*
	 * 实现EmbeddedValueResolverAware接口,实现其setEmbeddedValueResolver()方法,
	 * 使用StringValueResolver解析配置文件
	 */
	@Override
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		// TODO Auto-generated method stub
		this.stringValueResolver = resolver;
		this.driverClass = stringValueResolver.resolveStringValue("${db.driverClass}");

	}
}

4.创建一个测试类,添加一个测试方法test(),在方法中创建一个 AnnotationConfigApplicationContext对象并设置需要激活的环境。

public class ProfileTest {
	@Test
	public void test() {
		// 获取Spring的IOC容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//		// 设置要激活的环境
		applicationContext.getEnvironment().setActiveProfiles("development");
//		// 注册配置类
		applicationContext.register(SpringConfigOfProfile.class);
		applicationContext.refresh();
		// 从容器中获取bean
		String[] names = applicationContext.getBeanDefinitionNames();
		for (String i : names) {
			System.out.println(i);
		}
	}

5.运行结果:
在这里插入图片描述
可以看到加了@Profile注解标识的Bean,因为只有development环境被激活了,所以只注册了dataSourceOfDev到容器中。而没有加@Profile注解标识的Bean,在任何环境下都会注册到Spring IoC容器中。

当@Profile注解写在配置类上时,只有在指定的环境的时候,整个配置类里面的所有配置才能生效。
否则配置类中包括标识了@Bean的方法和@import注解定义的内容等配置信息都不会生效。

6.另一种激活环境的方式是直接配置运行环境,在运行配置中的VM参数添加-Dspring.profiles.active=test来激活test环境。ApplicationContext中配置激活的环境优先级大于这种方式。
在这里插入图片描述
添加测试方法test2:

	@Test
	public void test2() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
				SpringConfigOfProfile.class);
		// 从容器中获取bean
		String[] names = applicationContext.getBeanDefinitionNames();
		for (String i : names) {
			System.out.println(i);
		}
	}

运行这个测试方法,查看结果:
在这里插入图片描述
另外,在XML配置文件文件中可以这样配置环境:

<context-param>
  <param-name>spring.profiles.active</param-name>
  <param-value>test</param-value>
</context-param>

四、激活Profile的方式

注意:我们可以同时激活多个的Profile,如spring.profiles.active 可以接受以逗号分隔的配置文件名列表:

-Dspring.profiles.active="profile1,profile2"

或者向 setActiveProfiles ()方法提供多个配置文件名,该方法接受多个String类型参数:

applicationContext.getEnvironment().setActiveProfiles("profile1", "profile2");

Spring通过两个不同属性来决定哪些profile可以被激活,一个属性是spring.profiles.active和spring.profiles.default。这两个常量值在Spring的AbstractEnvironment中有定义。如果当spring.profiles.active属性被设置时,那么Spring会优先使用该属性对应值来激活Profile。当spring.profiles.active没有被设置时,那么Spring会根据spring.profiles.default属性的对应值来激活Profile。

可以使用 applicationContext.getEnvironment().setDefaultProfiles(profiles)或使用 spring.profiles.default 属性以声明方式更改默认Profile的名称。

如果上面的两个属性都没有被设置,那么就不会有任何Profile被激活,只有定义在Profile之外的Bean才会被创建。我们发现这两个属性值其实是Spring容器中定义的属性,而我们在实际的开发中很少会直接操作Spring容器本身,所以如果要设置这两个属性,其实是需要定义在特殊的位置,让Spring容器自动去这些位置读取然后自动设置,这些位置主要为如下定义的地方:

  • 作为SpringMVC中的DispatcherServlet的初始化参数
  • 作为Web 应用上下文中的初始化参数
  • 作为JNDI的入口
  • 作为环境变量
  • 作为虚拟机的系统参数
  • 使用@AtivceProfile来进行激活

参考:详解Spring中的Profile

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章