《Spring实战》-第三章:Bean的高级装配(1)-环境Profile

慢慢来比较快,虚心学技术

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配置方式暂不赘述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章