在IoC功能扩展点这篇文章中介绍了BeanFactoryPostProcessor及其使用方法,本篇介绍Spring官方提供的典型BeanFactoryPostProcessor。java
若是你的工程有不少配置内容放置到Java的标准配置文件*.properties中,当把Properties的内容整合到Spring中时就会用到PropertyPlaceholderConfigurer。PropertyPlaceholderConfigurer3个功能:git
PropertyPlaceholderConfigurer继承了配置BeanFactoryPostProcessor接口,在IoC开始初始化Bean以前修改对应BeanDefinition。在使用时咱们直接向容器添加一个PropertyPlaceholderConfigurer便可:spring
<!-- 启用占位符替换须要引入PropertyPlaceholderConfigurer --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <!-- 指定*.properties文件的路径 --> <property name="locations" value="classpath:project/config.properties"/> </bean> <!-- 替换Bean中的内容 --> <bean id="A" class="x.y.z.User"> <property name="name" value="${user.name}"/> <property name="address" value="${user.address}"/> <property name="age" value="${user.age}"/> </bean>
对应的config.properties文件中的内容:json
user.name='Alice' user.address='China' user.age=20
除了直接引入一个Bean,能够经过全局上下文配置启动这一项功能:bash
<context:property-placeholder location="classpath:project/config.properties"/>
前面说了PropertyPlaceholderConfigurer除了会用*.properties文件中的参数去替换占位符的内容,还会使用环境变量(System.getProperty(key))中的参数去替换。若是一个参数在配置文件中和系统环境变量中都存在,那么默认会使用*.properties中的参数来替换配置中的占位符。能够使用PropertyPlaceholderConfigurer::systemPropertiesMode来修改这个行为。他接受3个参数:ide
能够这样设置:ui
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <!-- 优先使用环境变量中的参数 --> <property name="systemPropertiesMode" value="2"/> </bean>
除了经过环境变量和*.properties配置文件引入参数,还能够直接写在XML的配置上:this
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <!-- 加载资源文件位置 --> <property name="locations"> <value>classpath:myProject/config.properties</value> </property> <!-- 动态添加配置参数 --> <property name="properties"> <value>define.runtime.class=x.y.z.A</value> </property> </bean> <!-- 动态加载一个类 --> <bean id="a" class="${define.runtime.class}"/>
上面XML配置还展现了一个动态装载类的方法。spa
PropertyOverrideConfigurer就是在PropertyPlaceholderConfigurer的基础上扩展了一些功能节约一些写配置文件的时间。他能够让你没必要在XML文件写占位符而直接注入数据。看下面的例子:code
经过<bean>标签引入了PropertyOverrideConfigurer类,而后有一个独立的User单例,以及将Cpu、Ram、Graphics单例组合到Pc中。
<beans> <!-- 引入PropertyOverrideConfigurer --> <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"> <property name="locations" value="classpath:xml/configoverride/config.properties"/> </bean> <!-- 配置Bean之间的组合关系 --> <bean id="user" class="chkui.springcore.example.xml.configoverride.User" /> <bean id="cpu" class="chkui.springcore.example.xml.configoverride.entity.Cpu" /> <bean id="ram" class="chkui.springcore.example.xml.configoverride.entity.Ram" /> <bean id="graphics" class="chkui.springcore.example.xml.configoverride.entity.Graphics" /> <bean id="pc" class="chkui.springcore.example.xml.configoverride.entity.Pc"> <property name="cpu" ref="cpu"/> <property name="ram" ref="ram"/> <property name="graphics" ref="graphics"/> </bean> </beans>
对应的*.properties配置是这样的:
user.name=Alice user.address=china user.age=20 pc.cpu.brand=AMD pc.graphics.brand=Nvdia pc.ram.brand=Kingston
Cpu类的结构:
package chkui.springcore.example.xml.configoverride.entity; public class Cpu { private String brand; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } }
这个时候PropertyOverrideConfigurer会根据容器中Bean的id或name来注入数据,好比*.properties配置中的"pc"就对应XML中的<bean id="pc">,接着pc中有一个域(成员变量)名为cpu那么它对应*.properties配置文件中"pc.cpu.",因此pc.cpu.brand=AMD的配置会告诉PropertyOverrideConfigurer向pc单例中的cpu实例的"brand"域注入数据"AMD"。
因此使用PropertyOverrideConfigurer运行以后,不须要在XML使用${property-name}这样的参数它会按照id或name的结构注入数据,此时user.getName() == "Alice"。若是类的关系是这个多层的结构同样能够根据Properties的结构注入数据,例如 pc.getPc().getBrand() == "AMD"。
例子的可执行代码见本人码云库中configoverride包。