Spring学习笔记-高级装配-03

主要内容:

  ●Spring profile

  ●条件化的bean声明

  ●自动装配与歧义性

  ● Spring表达式语言

本章介绍一些高级的装配技术,可实现更为高级的装配功能。

环境与profile

软件开发时,有一个很大的挑战就是讲应用程序从一个环境迁移到另外一个环境,开发环境可能并不适合迁移到生产环境,比如:数据库配置、加密算法以及外部系统的集成可能会发生变化。

比如数据库配置:

  ● 在开发环境中可能使用的是嵌入式数据库,并预先加载测试数据,bean配置类可能会在一个带有@Bean注解的方法上使用EmbeddedDatabasebuilder(嵌入式数据源)。

  ● 在生产环境中可能使用JNDI从容器中获取一个DataSource。

  ● 在测试环境中可能选择另外一个不同的DataSource。

在不同的还击某个bean因此不同,我们需要一种方法来配置DataSource,使其在不同环境中都会选择最合适的配置。

配置profile

Spring3.1版本中,引入了bean profile功能,要使用它,首先要将所有不同的bean定义整理到一个或多个profile中,在将应用部署到每个环境时,要确保对应的profile处于激活的状态。

使用配置类配置profile

在Java配置中,可使用@Profile注解指定某个bean属于哪一个profile,例如,在配置类中,

嵌入式数据库的DataSource配置

@Configuration
@Profile("dev") //告诉Spring这个配置类的bean只有在dev profile激活时才会创建,如果dev profile没有激活那么带有@Bean注解的方法都会被忽略掉
public class DevelopmentProfileConfig {
  @Bean
public DataSource dataSource(){ return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classppath:schema.sql") .addScript("classpath:test-data.sql") .build(); } }

一个适用于生产环境的配置

@Configuration
@Profile("prod") //告诉Spring这个配置类的bean只有在prod profile激活时才会创建,如果dev profile没有激活那么带有@Bean注解的方法都会被忽略掉
public class ProductionProfileConfig {
    @Bean
    public DataSource dataSource(){
        JndiObjectFactoryBean jndiObjectFactoryBean=
                new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName("jdbc/DS");
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource) jndiObjectFactoryBean;
    }
}

在Spring中,只能在类级别上使用@Profile注解,不过从3.2版本开始,也可以再方法级别使用@Profile,这样的话就能和@Bean同时使用,同时将两个bean的声明放在同一个配置类中。

@Profile注解基于激活的profile实现bean的装配

@Configuration
public class DataSourceProfile {
    @Bean
    @Profile("dev")  //为dev profile装配的bean
    public DataSource embededDataSource(){
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript("classppath:schema.sql")
            .addScript("classpath:test-data.sql")
            .build();
    }
    @Bean
    @Profile("prod") //为prod profile装配的bean
    public DataSource jndiDataSource(){
        JndiObjectFactoryBean jndiObjectFactoryBean=
                new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName("jdbc/DS");
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource) jndiObjectFactoryBean;
    }
}

使用XML配置profile

了解即可

激活profile

String在确定哪个profile处于激活状态时,需要依赖两个独立的属性:spring.profile.active和spring.profiles.default,如果设置了spring.profile.active属性,那么它的值就会用来确定哪个profile是激活的,如果没有设置,那就会查找spring.profiles.default的值,如果均没有设置那就没有激活的profile,则只会创建那些没用定义在profile中的bean。

有多种方式来设置这两个属性:

● 作为DispatcherServlet的初始化参数;

● 作为Web应用的上下文参数;

●  作为JNDI条目;

● 作为环境变量;

● 作为JVM的系统属性;

● 在集成测试类上,使用@ActiveProfiles注解设置。

在Web.xml文件中设置默认的profile

<Web-app version="2.5">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/root-context.xml</param-value>
    </context-param>
    
    <context-param>
        <param-name>spring.profiles.default</param-name>    <!-- 为上下文设置默认的profile -->
        <param-value>dev</param-value>
    </context-param>
    
    <listener>
        <listent-class>
            org.springframework.web.context.ContextLoaderListener
        </listent-class>
    </listener>
    
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>spring.profiles.default</param-name> <!-- 为Servlet设置默认的profile -->
            <param-value>dev</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</Web-app>

 按照这种方式设置spring.profiles.default,所有开发文员都能才能够版本控制软件获得应用程序代码,并且使用开发环境的设置运行代码,而不需要任何额外设置。

当程序部署到测试、生产或其他环境中,负责部署人员根据情况使用系统属性、环境变量或JNDI设置spring.profiles.active即可,此时spring.profiles.default值会被忽略,因为spring会优先使用spring.profiles.active的值。

使用profile进行测试

当集成运行测试时,通常会希望采用与生产环境相同的配置进行测试,但如果配置中的bean定义在profile中,那么在运行测试中,就需要有一种方式来启用合适的profile。

Spring提供了@ActiveProfiles注解,我们可使用它指定运行测试时要激活那个Profile。在集成测试时,通常想要激活的是开发环境的profile,例如,下面的测试类片段展现如何使用@ActiveProfile激活dev profile:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextCOnfiguration(classes={PersistenceTestConfig.class})
@ActiveProfiles("dev")
public class ActiveProfileTest {
....

条件化的Bean

  假设希望一个或多个bean只有在应用的类路径下包含特定的库时才会创建。或希望某个bean只有当另外某个特定的bean也声明后才会创建,以及等等需要满足各种条件才会创建。

在Spring4引入了一个新的@Conditional注解,它可以用到带有@Bean注解的方法上,如果给定的条件计算结果为true,就会创建这个bean,否则就会被忽略。

未完待续...

 

posted on 2018-05-21 21:52  奚云刀  阅读(174)  评论(0编辑  收藏  举报

导航