慢慢來比較快,虛心學技術
1.爲什麼需要profile?
實際開發中,生產環境和開發環境通常都不會是同一個,最明顯的例子就是,生產環境(正式環境)的數據庫和開發環境的數據庫一般都是不一樣的。那麼爲了方便配置的轉換,Spring提供了profile關鍵字進行統一的環境配置,通過profile配置我們可以快速的切換整個應用的環境,而不需要從代碼層面進行重新構建
那麼,使用profile的目的是爲了更方便的配置不同的環境,指定某些具體的類或組件的作用域
注:每個bean或組件都有默認的作用域default,如果沒有限定作用域,則這些bean都會被裝配,如果指定了作用域,則只有處在相應作用域(環境)中時纔會被裝配
2.怎麼配置profile?
JavaConfig顯式裝配或者自動裝配可以通過註解@Profile進行環境限制,比如:
Ⅰ、自動化裝配,我們將類DataSource的作用域限定爲只有當環境爲“prod”才被裝配,結合@Component註解和@Profile註解實現
代碼1.1
@Component
@Profile("prod")
public class DataSource {
/**
* 定義名稱
*/
private String name;
public DataSource(){
super();
}
public DataSource(String name){
this.name = name;
}
}
Ⅱ、JavaConfig顯式配置,有兩種實現方式
- 第一種:在指定多個配置類,在配置類上指定作用域,其內所定義的所有Bean只能在該作用域下被裝配,進行環境統一配置
代碼1.2
//1.創建一個配置類DevConfig,並將其作用域設置爲dev,則其內定義的Bean只有在環境爲dev的時候纔可以被裝載
@Configuration
@Profile(value = "dev")
public class DevConfig {
//定義一個name屬性爲Dev DataSource的Bean
@Bean
public DataSource dataSource(){
return new DataSource("Dev DataSource");
}
}
//2.創建一個配置類ProdConfig,並將其作用域設置爲prod,則其內定義的Bean只有在環境爲prod的時候纔可以被裝載
@Configuration
@Profile(value = "prod")
public class ProdConfig {
//定義一個name屬性爲Dev DataSource的Bean
@Bean
public DataSource dataSource(){
return new DataSource("Prod DataSource");
}
}
//3.創建一個默認配置類,當系統未指定系統環境時,將默認使用該配置
@Configuration
public class DefaultConfig {
@Bean
public DataSource dataSource(){
return new DataSource("Default DataSource");
}
}
//4.創建一個統一配置類SystemConfig,並將三個配置類引入,因爲各自定義了作用域(DefaultConfig未明文指定),所以引入並不會導致衝突
@Configuration
@Import({DevConfig.class,ProdConfig.class,DefaultConfig.class})
public class SystemConfig {}
- 第二種:除了在類上使用@Profile指定類作用域之外,@Profile還可以在方法上使用,在JavaConfig結合@Bean進行裝配環境的限制
代碼1.3
@Configuration
public class SystemConfig {
@Bean
@Profile("dev")//當系統環境爲dev的時候,使用該Bean方法進行裝配
public DataSource devDataSource(){
return new DataSource("Dev DataSource");
}
@Bean
@Profile("prod")//當系統環境爲prod的時候,使用該Bean方法進行裝配
public DataSource prodDataSource(){
return new DataSource("Prod DataSource");
}
@Bean//默認裝配
public DataSource defaultDataSource(){
return new DataSource("Default DataSource");
}
}
Ⅲ、XML配置Profile,和JavaConfig類似也有兩種方式
- 第一種:爲每一個配置文件的<beans>配置Profile,只有在固定對應環境下配置文件纔會生效(比較常用)
代碼1.4
//1、創建配置文件DevConfig.xml,並在<beans>節點設置profile屬性爲dev,只有在環境爲dev的時候本配置文件生效
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
profile="dev"
>
<bean class="com.my.spring.bean.DataSource" name="dataSource">
<constructor-arg name="name" value="Dev DataSource"></constructor-arg>
</bean>
</beans>
//2、創建配置文件ProdConfig.xml,並在<beans>節點設置profile屬性爲prod,只有在環境爲prod的時候本配置文件生效
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
profile="prod"
>
<bean class="com.my.spring.bean.DataSource" name="dataSource">
<constructor-arg name="name" value="Prod DataSource"></constructor-arg>
</bean>
</beans>
//3、創建配置文件DefaultConfig.xml,默認加載
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.my.spring.bean.DataSource" name="dataSource">
<constructor-arg name="name" value="Default DataSource"></constructor-arg>
</bean>
</beans>
//4、創建系統配置文件,將上述三個配置文件引入,因爲限定了環境,所以並不會衝突
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="DefaultConfig.xml"/>
<import resource="DevConfig.xml"/>
<import resource="ProdConfig.xml"/>
</beans>
- 第二種:在同一個配置文件中指定不同的<beans>設定profile屬性,所包裹的bean只有在指定環境下才會被裝配
代碼1.5
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<description>Spring配置文件</description>
<beans>
<bean id="dataSource" name="default" class="com.my.spring.bean.DataSource">
<constructor-arg name="name" value="Default DataSource"></constructor-arg>
</bean>
</beans>
<beans profile="dev">
<bean id="dataSource" name = "dev" class="com.my.spring.bean.DataSource">
<constructor-arg name="name" value="Dev DataSource"></constructor-arg>
</bean>
</beans>
<beans profile="prod">
<bean id="dataSource" name="prod" class="com.my.spring.bean.DataSource">
<constructor-arg name="name" value="Prod DataSource"></constructor-arg>
</bean>
</beans>
</beans>
3、如何激活profile?
如上述配置每個配置文件或者JavaConfig,Bean等的profile屬性後,如何設定一個系統所處的環境呢?
Spring提供了多種方式:
作爲 DispatcherServlet 的初始化參數;
作爲 Web 應用的上下文參數;
作爲 JNDI 條目;
作爲環境變量;
作爲 JVM 的系統屬性;
在集成測試類上,使用 @ActiveProfiles 註解設置;
- 此處先了解@ActiveProfiles註解方式
在上一章中,我們瞭解到,Spring測試使用@RunWith(SpringJUnit4ClassRunner.class)和@ContextConfiguration註解進行應用上下文注入測試,在測試中我們可以通過結合@ActiveProfiles註解進行測試環境的配置,具體代碼如下:
以自動化裝配模式爲例:
上述代碼1.1中指定DataSource只有在prod環境下才會被裝載,故在測試中將系統環境分別指定爲prod和dev測試DataSource的Bean是否會裝配
代碼1.6
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,classes = {ComponentConfig.class})
@ActiveProfiles("prod")//指定系統環境爲prod
public class AppComponentTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void testGetBean(){
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String beanName : beanDefinitionNames){
System.out.println(beanName);
}
}
}
測試結果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentConfig
dataSource //dataSource被裝配
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,classes = {ComponentConfig.class})
@ActiveProfiles("dev")//指定系統環境爲dev
public class AppComponentTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void testGetBean(){
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String beanName : beanDefinitionNames){
System.out.println(beanName);
}
}
}
//dataSource未被裝配
測試結果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentConfig
再以JavaConfig顯式裝配爲例,設定不同的profile測試獲取到的dataSource是否一致,以代碼1.3作爲系統配置:
代碼1.7
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,classes = {SystemConfig.class})
@ActiveProfiles("prod")//指定系統配置環境爲prod
public class AppConfigTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void testGetBean(){
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String beanName : beanDefinitionNames){
System.out.println(beanName);
}
}
}
測試結果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
systemConfig
prodDataSource //證明獲取的是prod環境的dataSource
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,classes = {SystemConfig.class})
@ActiveProfiles("dev")//指定系統配置環境爲dev
public class AppConfigTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void testGetBean(){
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for(String beanName : beanDefinitionNames){
System.out.println(beanName);
}
}
}
測試結果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
systemConfig
devDataSource //證明獲取的是dev環境的dataSource
- 由於未瞭解到網絡模塊,所以web配置方式暫不贅述