Spring学习笔记9_环境抽象(Environment Abstraction)

文章参考来源:Spring Framework官方文档

关于Environment(org.springframework.core.env.Environment) ,它是集成在容器中的一个抽象接口,它的使用体现在应用程序环境的两个方面:概要文件和属性profiles and properties)。

  • 概要文件是一个命名的、逻辑的bean定义组,只有在给定的概要文件是active活动的情况下才向容器注册。无论是用XML定义的还是用注释定义的bean,都会被分配给一个概要文件。与概要文件相关的Environment对象的作用是确定哪些概要文件(如果有的话)当前是活动的,以及哪些概要文件(如果有的话)在默认情况下应该是活动的

  • 属性在几乎所有的应用程序中都扮演着重要的角色,它可能起源于各种来源:属性文件、JVM系统属性、系统环境变量、JNDI、servlet上下文参数、特别的Properties对象、Map对象等等。与属性相关的Environment对象的作用是为用户提供方便的服务接口,用于配置属性源并从它们解析属性

概括来说,Environment 的作用就是:区分active环境,并配置解析对应属性。

1. Profile

(1)@Profile的使用

@Profile注解,用来标注active环境。比如以下例子中,不同环境下使用的数据库不同:

@Configuration
@Profile("development")
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");
    }
}

@Profile注解括号中的string,可以是profile name也可以是profile 表达式。profile 表达式允许一些复杂的表达式逻辑,比如“production & us-east”,其中:

  • !表示“非”,not
  • &表示“与”,and
  • |表示“或”,or

以上表达式支持混合使用,比如production & us-east | eu-central或者production & (us-east | eu-central)

甚至可以支持自定义注解来标注环境,比如使用@Profile注解生成一个@Production注解,标注其环境名为:production

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

@Profile注解不仅可以用在配置类上,也可以使用在方法级别,比如:

@Configuration
public class AppConfig {

    @Bean("dataSource")
    @Profile("development") 
    public DataSource standaloneDataSource() {
        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("dataSource")
    @Profile("production") 
    public DataSource jndiDataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}

profile不仅可以在java代码中以注解方式起作用(@Profile),也可以在XML配置profile属性:

<beans profile="development"
    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>

profile属性也可以在同一个文件中体现:

<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="development">
        <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>

(2)激活Profile

激活方式:

  • (1)利用ApplicationContext
  • (2)配置文件中设置属性:spring.profiles.active
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();

甚至可以激活多个profile:

ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
-Dspring.profiles.active="profile1,profile2"

默认的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出于active状态,那么dataSource会被创建。哪怕只有一个profile出于active,那么默认的profile将不会起效。
如果想修改默认profile,可以选择Environment的setDefaultProfiles()方法,或者设置spring.profiles.default属性。

2. PropertySource

(1)关于PropertySource的简单理解

PropertySource是对任何键值对源的一个简单抽象
Spring的StandardEnvironment配置了两个PropertySource对象——一个表示JVM系统属性集(system . getproperties()),另一个表示系统环境变量集(system .getenv())。

对于独立应用程序而言,StandardEnvironment能够提供默认属性源。像StandardServletEnvironment,它使用了额外的默认属性源,包括servlet配置和servlet上下文参数。它甚至可以选择性启用一个JndiPropertySource。

可以自定义添加自己的PropertySource,比如:

ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());

(2)@PropertySource注解的使用

@PropertySource为将PropertySource添加到Spring环境提供了一种简单方便的声明性机制。
在下面的例子中,假设文件app.properties中包含键值对属性为:testbean.name=myTestBean,以下@Configuration配置类使用@PropertySource注解,将testbean.name引入并注入到testBean的name上:

@Configuration
@PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {

    @Autowired
    Environment env;

    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("testbean.name"));
        return testBean;
    }
}

关于语句中的占位符

  • 之前,占位符的解析只能根据JVM系统属性或环境变量。(也就是只有在JVM系统属性或环境变量中设置过的占位符值,才可以被解析到)
  • 现在情况不再是这样了。因为Environment抽象方法在整个容器中集成,所以很容易通过它来路由占位符的解析。
  • 这意味着可以以任何方式配置解析过程。甚至可以更改搜索系统属性和环境变量的优先级,或者完全删除它们。还可以根据需要将自己的属性源添加到该组合中。

也就是说,无论自定义属性在哪里定义,只要它在Environment环境中可用,那么声明都是可解析有效的:

<beans>
    <import resource="com/bank/service/${customer}-config.xml"/>
</beans>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值