Spring基础九:环境Environment

在继续讲解基于注解(@Value)的属性配置之前,我们先介绍Spring的Environment,否则@Value的属性来源会讲不清楚。这与官方文档的顺序有所不同。本章内容对应官方文档地址

Environment是对Spring运行的外部环境抽象,Environment主要管理两个概念:profiles和properties。

Profile

要准确给Pofile下一个定义还挺难的,官方文档认为Pofile可以理解为若干bean集合的逻辑组名称,而我认为可理解为Spring容器的运行时标签。我们不妨先了解了Profile如何使用,然后自就在头脑中建立起对它的认知。

激活Profile

Spring可以同时激活一个或多个Profile,他们记录在Environment里,激活一个Profile最直接的是调用Environment接口:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");

另外就是通过设定spring.profiles.active属性,如果通过命令行参数的话,类似这样:
-Dspring.profiles.active="profile1,profile2"

默认Profile

如果没有激活任何Proifle,那么名叫“default”的profile会被激活。可以通过ctx.getEnvironment().setDefaultProfiles方法或者java系统属性spring.profiles.default来修改。

Profile机制

Profile给Spring提供了一种机制,在不同的环境里注册不同的Bean,比如:

  1. 在开发环境使用In-memory数据库,在QA以及生产环境从JNDI查找数据源;
  2. 在性能测试环境在注册那些性能检测的bean;
  3. 企业软件对不同的客户部署定制化的bean。

满足上面第一个需求的代码类似:

@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可以放在@Configuration类上面,也可以放在@Bean方法上面。一旦附加了@Profile,那么只有指定的Profile被激活时,该@Configuration或@Bean才有效。

逻辑操作符

@Profile注解支持逻辑操作:

  • @Profile(!profile), 逻辑非,代表当profile没有激活;
  • @Profile(profileA&profileB),逻辑与,代表当profileA和profileB都激活;
  • @Profile(profileA|profileB),逻辑或,代表当profileA或profileB被激活;
  • @Profile({profileA,profileB}),逗号分隔的多个profile,相当于逻辑或

和java的逻辑操作符类似,可以组合这些操作符,通过括号来界定优先级。

Properties

Property是具名的值,也即name&value名值对。Spring容器定义了一个全局统一的Property查询接口:

ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
String pvalue = env.getProperty("my-property");

虽然用统一的方式查询,但属性有多种来源,实际上,Environment抽象了一个可配置的、包含多种属性源层级结构。属性源对应的java定义是PropertySource。

PropertySource

Spring包含多种Environment实现,分别预设了不同的PropertySource,这些PropertySource是有序的,排在前面的有更高的优先级。比如StandardEnvironment,配置了两个源:JVM系统属性和系统环境变量,它的源码一看就明白:

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
	propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
	propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

而StandardServletEnvironment,则包含以下属性源(按顺序):

  1. ServletConfig参数
  2. ServletContext配置参数
  3. JNDI环境变量
  4. JVM系统属性
  5. JVM环境变量

添加PropertySource

我们可以添加自己的PropertySource到Environment,下面的代码将MyPropertySource添加为Environment的第一个PropertySource,使其具备最高的优先级:

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

在配置类上通过注解@PropertySource可以添加读取属性文件的PropertySource:

@Configuration
@PropertySource(value = {"classpath:propertySource.properties"})
public class AppConfig {
}

总结

Sping的环境被抽象为Environment,Environment主要管理两个概念,Profile和Properties。Profile是Spring的容器的标签机制,通过激活不同的Profile,我们可以基于同一套代码在运行时激活不同的bean。Properties是Spring容器范围内共享的名值对,它来自多个PropertySource,我们可以添加自定义的PropertySource。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值