In the first two posts of this series, I described the bean definition profiles feature, and how it relates to the Environment abstraction new in Spring 3.1 M1. Today we’ll take a look at a second aspect of the Environment – how it helps simplify the concern of configuration property management.

Understanding property sources

Spring’s Environment abstraction provides search operations over a configurable hierarchy of property sources. To explain fully, consider the following:


ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean containsFoo = env.containsProperty("foo");
System.out.println("Does my environment contain the 'foo' property? " + containsFoo);

In the snippet above, we see a high-level way of asking Spring whether the ‘foo’ property is defined for the current environment. To answer this question, the Environment object performs a search over a set of PropertySource objects. A PropertySource is a simple abstraction over any source of key-value pairs, and Spring’s DefaultEnvironment is configured with two PropertySource objects – one representing the set of JVM system properties (a la System.getProperties()) and one representing the set of system environment variables (a la System.getenv())[1]. This means that if a ‘foo’ system property or ‘foo’ environment variable is present at runtime, the call to env.containsProperty(“foo”)will return true.

The search performed is hierarchical. By default, system properties have precedence over environment variables, so if the ‘foo’ property happens to be set in both places during a call toenv.getProperty(“foo”), the system property value will ‘win’ and be returned preferentially over the environment variable.

Most importantly, the entire mechanism is configurable. Perhaps you have a custom source of properties that you’d like to integrate into this search. No problem – simply implement and instantiate your own PropertySource and add it to the set of PropertySources for the current Environment:


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

In the code above, MyPropertySource has been added with highest precedence in the search. If it contains a ‘foo’ property, it will be detected and returned ahead of any ‘foo’ property in any other PropertySource. The MutablePropertySources API exposes a number of methods that allow for precise manipulation of the set of property sources. Explore the Javadoc for full details.

Putting property sources to use

Now that you understand the basics of property sources and their relationship to theEnvironment, you might be wondering how all of this is relevant to you as a developer of Spring applications. Let’s consider a couple of scenarios and see how it all comes together.

Scenario 1: ${placeholder} resolution in statements

You have a set of Spring configuration files that configure beans specific to certain customers of your application, and you conditionally load those files using statements containing a placeholder resolving to the value of a ‘customer’ property:


<beans>
<import resource="com/bank/service/${customer}-config.xml"/>
</beans>

Prior to Spring 3.1, the value of placeholders in elements could be resolved only against JVM system properties or environment variables[2]. No longer is this the case. Because theEnvironment abstraction is integrated throughout the container, it’s easy to route resolution of placeholders through it. This means that you may configure the resolution process in any way you like: change the precedence of searching through system properties and environment variables, or remove them entirely; add your own property sources to the mix as appropriate.

Scenario 2: ${placeholder} resolution in bean definitions

Most Spring users will be familiar with the use of PropertyPlaceholderConfigurer or<context:property-placeholder/> to replace ${…} placeholders in Spring bean definitions. Here is a typical configuration:


<context:property-placeholder location="com/bank/config/datasource.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClass" value="${database.driver}"/>
<property name="jdbcUrl" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>

As of Spring 3.1, the <context:property-placeholder/> no longer registers aPropertyPlaceholderConfigurer, but rather a PropertySourcesPlaceholderConfigurer[3]. This component still looks to the datasource.properties file to reslove the ${database.*}placeholders above, but will fall back to the set of PropertySources for the currentEnvironment if the properties are not found in the file. Again this gives you more control; prior to this change, the only fallback options were system properties and environment variables.

Manipulating property sources in a web application

So far we’ve seen how to access and manipulate property sources in a standalone application where we have programmatic access to an ApplicationContext. In reality, however, many Spring applications are webapps in which the ApplicationContext is managed for you by Spring’s ContextLoaderListener. For this reason we’ve introduced theApplicationContextInitializer interface and its companion, thecontextInitializerClasses servlet context param. Take a look:

web.xml


<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.bank.MyInitializer</param-value>
</context-param>

public class MyInitializer implements ApplicationContextInitializer<ConfigurableWebApplicationContext> {
public void initialize(ConfigurableWebApplicationContext ctx) {
PropertySource ps = new MyPropertySource();
ctx.getEnvironment().getPropertySources().addFirst(ps);
// perform any other initialization of the context ...
}
}

Implementing and registering an ApplicationContextInitializer provides a simple way to interact with your application context before it is refreshed. This is a perfect place to manipulate property sources, but you could also call setConfigLocations(…) or any other method designed to be called prior to refresh().

Summary

Spring’s Environment abstraction provides a single location to configure both profiles andproperties. Profiles, as described in earlier posts, determine which bean definitions should be registered for a given deployment context; the property support described in this post provides a consistent abstraction over any source of properties, resulting in more flexible property access and placeholder resolution throughout your application configuration.

In the next post in this series we’ll take a look at how Spring 3.1 makes 100% Java-based (read: XML-free) application configuration a reality with FeatureSpecification support – an natural evolution out of the @Configuration class support introduced in Spring 3.0.

Footnotes

[1]: These default property sources are present for DefaultEnvironment, for use in standalone applications. DefaultWebEnvironment is populated with additional default property sources including servlet config and servlet context parameters. DefaultPortletEnvironmentsimilarly has access to portlet config and portlet context parameters as property sources. Both can optionally enable a JndiPropertySource. See Javadoc for details.

[2]: Because processing of elements necessarily occurs before BeanFactoryPostProcessorsare invoked, meaning that even PropertyPlaceholderConfigurer could not help here. Because the Environment and its set of PropertySources are configured before container refresh, placeholders in elements can be resolved against the Environment without any lifecycle issues.

[3]: In certain cases, <context:property-placeholder/> will still register aPropertyPlaceholderConfigurer. In the 3.1 version of the spring-context schema, thesystem-properties-mode attribute has been removed from the property-placeholderelement. This is because this attribute no longer makes sense in a PropertySources-/Environment-aware world. However, if you build against Spring 3.1 but still use thespring-context-3.0.xsd schema and set the system-properties-mode attribute,<context:property-placeholder> will revert to registering aPropertyPlaceholderConfigurer in order to honor the exact semantics of this setting. This approach preserves backward compatibility in any case.

Spring 3.1 M1: Unified Property Management(转)的更多相关文章

  1. Spring利用propertyConfigurer类 读取.property数据库配置文件

    (1).基本的使用方法是: <bean id="propertyConfigurerForAnalysis" class="org.springframework. ...

  2. Use Spring transaction to simplify Hibernate session management

    Spring对Hibernate有很好的支持    DataSource ->SessionFactory-> HibernateTranscationManagerHibernate中通 ...

  3. spring 配置文件 引入外部的property文件的两种方法

    spring  的配置文件 引入外部的property文件的两种方法 <!-- 引入jdbc配置文件    方法一 --> <bean id="propertyConfig ...

  4. spring boot 遇到 supported setting property http://xml.org/sax/properties/lexical-handler

    解决链接:http://apache-fop.1065347.n5.nabble.com/org-xml-sax-SAXNotSupportedException-thrown-by-FOP-td11 ...

  5. Spring框架中<constructor-arg>与<property>理解

    配置文件的根元素是beans,每个组件使用bean元素来定义,bean元素可以有许多属性,其中有两个是必须的:id和class.id表示组件的默认名称,class表示组件的类型. 依赖注入的方式:  ...

  6. spring data jpa 查询No property ... found for...Did you mean '...'?

    原文地址:https://blog.csdn.net/earthhour/article/details/79271816 实体类字段定义: private String sku_no; dao中接口 ...

  7. Spring 注解 hibernate 实体方法 <property name="packagesToScan" value="com.sise.domain"/>

    <property name="annotatedClasses"> <list> <value>com.sise.domain.Admin&l ...

  8. Spring Boot 2.x中的management.security.enabled=false无效问题

    look: https://blog.csdn.net/qq_27385301/article/details/82899303

  9. 【Spring实战】----开篇(包含系列目录链接)

    [Spring实战]----开篇(包含系列目录链接) 置顶2016年11月10日 11:12:56 阅读数:3617 终于还是要对Spring进行解剖,接下来Spring实战篇系列会以应用了Sprin ...

随机推荐

  1. 关于windows2008r2系统80端口被system进程占用的问题

    80端口被system占用的问题   今天启动tomcat的时候发现无法启动80端口被占用 通过netstat -ano查看,发现被pid=4的进程占用 检查进程发现是system进程pid=4给占用 ...

  2. 通达OA系统myisam转innodb引擎

    OA系统切换到linux环境后,性能提升了2-3倍左右,随着公司的发展壮大,办公人员也会越来越多,当人数达到一定数量级别时如1500在线人数已无法支撑公司业务,就需要对系统进行性能提升优化. 当前OA ...

  3. 转载:2.2.3 配置项的注释《深入理解Nginx》(陶辉)

    原文:https://book.2cto.com/201304/19628.html 如果有一个配置项暂时需要注释掉,那么可以加"#"注释掉这一行配置.例如: #pid       ...

  4. 转载:磁盘目录(1.3.3)《深入理解Nginx》(陶辉)

    原文:https://book.2cto.com/201304/19614.html 要使用Nginx,还需要在Linux文件系统上准备以下目录. (1)Nginx源代码存放目录 该目录用于放置从官网 ...

  5. Android开源动画库nineoldandroids

    项目官网地址:http://nineoldandroids.com/ 使用这个库的原因是android3.0之后出了新的animation API,但是android3.0以下的不支持 这个库完成了这 ...

  6. 搭建ssh框架项目(四)

    一.创建控制层 (1)创建VO值对象,对应页面表单的属性值 package com.cppdy.ssh.web.form; /** * VO值对象,对应页面表单的属性值 * VO对象与PO对象的关系: ...

  7. 并发之synchronized关键字的应用

    并发之synchronized关键字的应用 synchronized关键字理论基础 前两章我们学习了下java内存模型的相关知识, 现在我们来讲讲逢并发必出现的synchronized关键字. 作用 ...

  8. Laravel Cache 缓存钉钉微应用的 Access Token

    钉钉微应用的 Access token 如何获取? Access_Token 是企业访问钉钉开放平台全局接口的唯一凭证,即调用接口时需携带Access_Token.从接口列表看,所有接口都需要携带 a ...

  9. MVC开发中的常见错误-03-System.Data.Entity.Validation.DbEntityValidationException: 对一个或多个实体的验证失败。有关详细信息,请参见“EntityValidationErrors”属性。

    return Db.SaveChanges()>0; return CurrentDBSession.SaveChanges(); RoleInfoService.EditEntity(role ...

  10. 【APUE | 08】进程控制

    函数fork 博文链接: 1. 代码示例: #include "apue.h" ; char buf[] = "a write to stdout\n"; in ...