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

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