分析
SPRING通过
1.property-placeholder spring3.1以前实现是PropertyPlaceholderConfigurer,3.1以后是PropertySourcesPlaceholderConfigurer
<context:property-placeholder local-override="true" properties-ref="dataSourceProperties"
file-encoding="UTF-8" location="classpath:loc/config.properties"
ignore-resource-not-found="true" />
2 3.1后PropertySourcesPlaceholderConfigurer支持加载通配符*
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer
" p:location="classpath*:
loc/*.properties"></bean>
按ctrl点击标签可以看到spring-context.xsd中的详细信息。
PropertySourcesPlaceholderConfigurer类经过一系列继承关系,实质是一个容器后管理器。debug走里面的一段代码如下:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertySources == null) {
this.propertySources = new MutablePropertySources();
if (this.environment != null) {
this.propertySources.addLast(new PropertySource<Environment>("environmentProperties", this.environment) {
@Nullable
public String getProperty(String key) {
return ((Environment)this.source).getProperty(key);
}
});
}
try {
PropertySource<?> localPropertySource = new PropertiesPropertySource("localProperties", this.mergeProperties());
if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
} else {
this.propertySources.addLast(localPropertySource);
}
} catch (IOException var3) {
throw new BeanInitializationException("Could not load properties", var3);
}
}
this.processProperties(beanFactory, (ConfigurablePropertyResolver)(new PropertySourcesPropertyResolver(this.propertySources)));
this.appliedPropertySources = this.propertySources;
}
进入这个mergeProperties()方法里面看:
protected Properties mergeProperties() throws IOException {
Properties result = new Properties();
if (this.localOverride) {
this.loadProperties(result);
}
if (this.localProperties != null) {
Properties[] var2 = this.localProperties;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Properties localProp = var2[var4];
CollectionUtils.mergePropertiesIntoMap(localProp, result);
}
}
if (!this.localOverride) {
this.loadProperties(result);
}
return result;
}
可以看到localOverride这个属性是用来控制是否覆盖Spring读取的属性配置。并且下面紧跟着判断this.localProperties!=null,如果localProperties不为null的话,会读取这些配置信息到spring容易中并且覆盖spring中已存在的属性。
<!-- 这里的local-override="true" 就是覆盖spring容器中已存在的属性,properties-ref="dataSourceProperties" 是指定自己的properties -->
<context:property-placeholder local-override="true" properties-ref="dataSourceProperties"
file-encoding="UTF-8" location="classpath:loc/config.properties"
ignore-resource-not-found="true" />
<!-- 这个类是我自定义的,用来解密jdbc.properties中的属性之后然后存放到Properties类中 -->
<bean id="dataSourceProperties" class="com.spring.demo.utils.DataSourceProperties">
<constructor-arg value="encrypt.jdbc.password"/>
</bean>
下面是我的DataSourceProperties类
package com.spring.demo.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Properties;
/**
* 数据源配置参数处理
* <p/>
* 配置信息事先被DES加密处理,需要在此解密然后绑定到数据源
* Created by Alvin on 2016/7/31.
*/
public class DataSourceProperties extends Properties {
protected static final Logger logger = LoggerFactory.getLogger(AesUtils.class);
/**
* 构造方法
* @param propertyNames 需要解密的属性名称
*/
public DataSourceProperties(String[] propertyNames) {
try {
this.load(DataSourceProperties.class.getClassLoader()
.getResourceAsStream("loc/config.properties"));
for (String propertyName : propertyNames) {
decrypt(propertyName);
}
} catch (IOException e) {
logger.error(e.getMessage(),e);
}
}
/**
* 解密
*/
private void decrypt(String propertyName) {
logger.info("propertyName({}),value({})",propertyName,this.getProperty(propertyName));
if (isEncryptPropertyVal(propertyName)){
String value = AesUtils.decrypt(this.getProperty(propertyName), AesUtils.key);
logger.info("propertyName({}),propertyValue({}),",propertyName,value);
this.setProperty(propertyName, value);
}
}
/**
* 判断属性值是否需要解密,这里我约定需要解密的属性名用encrypt开头
* @param propertyName
* @return
*/
private boolean isEncryptPropertyVal(String propertyName){
if(propertyName.indexOf("encrypt") >= 0){
return true;
}else{
return false;
}
}
}