译--Spring中 bean定义profiles的使用 javaConfig 和XML配置

原文地址:http://docs.spring.io/spring/docs/5.0.0.M4/spring-framework-reference/htmlsingle/#beans-property-source-abstraction
bean定义profiles是核心容器内的一种机制,该机制能在不同环境中注册不同的bean。环境的意思是,为不同的用户做不同的事儿,该功能在很多场景中都非常有用,包括:

  • 开发期使用内存数据源,在QA或者产品上则使用来自JNDI的相同的数据源
  • 开发期使用监控组件,当部署以后则关闭监控组件,是应用更高效
  • 为用户各自注册自定义bean实现

考虑一个实际应用中的场景,现在需要一个DataSource。开测试环境中,这样配置:

@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.HSQL)
        .addScript("my-schema.sql")
        .addScript("my-test-data.sql")
        .build();
}

现在让我们考虑如何将此应用程序部署到QA或生产环境中,假设应用程序的数据源将注册到生产应用程序服务器的JNDI目录。 我们的dataSource bean现在看起来像这样:

@Bean(destroyMethod="")
public DataSource dataSource() throws Exception {
    Context ctx = new InitialContext();
    return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}

问题是,在当前环境中如何切换这两个配置。随着时间推移,Spring用户设计了很多种方式完成此切换,通常使用系统环境变量和XML<import/>绑定,<import/>元素包含一个${placeholder}符号,使用环境变量来设置${placeholder}符号所代表的值,从而达到切换正确配置文件的目的。bean定义profiles是核心容器功能,提供针对子问题的解决方案。

概括一下上面的场景:环境决定bean定义,最后发现,我们需要在某些上下文环境中使用某些bean,在其他环境中则不用这些bean。你也许会说,你需要在场景A中注册一组bean定义,在场景B中注册另外一组。先看看我们如何修改配置来完成此需求。

@Profile

@Profile注解用于当一个或多个配置文件激活的时候,用来指定组件是否有资格注册。 使用上面的例子,我们可以重写dataSource配置如下:

@Configuration
@Profile("dev")
public class StandaloneDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }
}
@Configuration
@Profile("production")
public class JndiDataConfig {

    @Bean(destroyMethod="")
    public DataSource dataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}

如前所述,使用@Bean方法,通常会选择使用JNDI查找:使用Spring的JndiTemplate /JndiLocatorDelegatehelper或上面显示的直接JNDIInitialContext用法,但不是JndiObjectFactoryBean 这将使你声明返回类型必须为FactoryBean类型

@Profile可以用作meta-annotation,用于创建自定义组合注解。 下面的例子定义了一个自定义@Production注解,该注解用于替换

@Profile("production"):

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @interface Production {
}

@Profile也能注解方法,用于配置一个配置类中的指定bean:

@Configuration
public class AppConfig {

    @Bean
    @Profile("dev")
    public DataSource devDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }

    @Bean
    @Profile("production")
    public DataSource productionDataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}

如果@Configuration类标有@Profile,类中@Bean@Import注解相关的类都将被忽略,除非该profile被激活。 如果一个@Component@Configuration类被标记为@Profile({“p1”,“p2”}),那么除非profile'p1'和/或’p2’ 已被激活。否则该类将不会注册/处理。 如果给定的配置文件以NOT运算符(!)为前缀,如果配置文件为 not active,则注册的元素将被注册。 例如,给定@Profile({“p1”,“!p2”}),如果配置文件’p1’激活或配置文件’p2’没有激活,则会注册。

XML bean 定义 profiles

XML配置是作为<beans> 的一个属性, 我们上面的示例配置能够用下面的两个XML文件来重写, 如下:

<beans profile="dev"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xsi:schemaLocation="...">

    <jdbc:embedded-database id="dataSource">
        <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
        <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
    </jdbc:embedded-database>
</beans>
<beans profile="production"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>

避免上面两个文件分开也是有可能的, 通过在相同的文件中嵌套<beans/> 元素。

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <!-- other bean definitions -->

    <beans profile="dev">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
            <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
        </jdbc:embedded-database>
    </beans>

    <beans profile="production">
        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
    </beans>
</beans>

激活profile

既然我们已经更新了配置, 我们仍然需要告知Spring哪一个profile 是激活的。 如果我们现在就启动我们的示例应用, 我们将会看到NoSuchBeanDefinitionException 抛出, 因为容器不能找到名为dataSource 的Spring bean。

可以采用一些方式激活profile, 但是最直接的方式是依靠Environment API用编程方式来配置,通过ApplicationContext 来获取Environment

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("dev");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();

另外, profiles 可能通过spring.profiles.active 属性来声明式的激活, 此属性可能在系统环境变量, JVM系统属性, web.xml 定义的 servlet上下文参数中被指定, 或着甚至可以作为JNDI的一个元组(entry), 在集成测试中。 在spring-test 模块中可以通过@ActiveProfiles 注解来激活profiles。

注意 profiles 并不是“或着-或着”的命题, 一次性激活多个profiles也是有可能的, 编程式地,简单的向setActiveProfiles() 方法中提供多个profile名称, 它接受String... 参数:

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

声明式地配置,spring.profiles.active 可以接受以逗号分隔的profile名称列表:

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

默认profile

默认profile 表示这个profile默认的被启用。如下:

@Configuration
@Profile("default")
public class DefaultDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .build();
    }
}

如果没有profile被激活, 那么上面的dataSource 将会被创建; 这可以被看作是为一个或多个beans提供一个默认定义 的一种方式。如果有任一bean被激活, 默认profile将不会生效。

默认profile的名称可以被改变, 在Environment中使用setDefaultProfiles() , 或着声明式的使用spring.profiles.default 属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值