以前知道有<context:property-placehoder />,但始终不甚明白Spring定义bean时是怎么把properties中的属性值读进去的,有时候将属性放在System里面时而可以时而不行。
今天查看下源代码结构:
PropertyPlaceholderConfigurer 》PlaceholderConfigurerSupport 》PropertyResourceLoader implementsBeanFactoryPostProcessor
当然,PropertyResourceLoader 还继承了PropertyLoaderSupport,在后者中,有个propertiesPersister对象负责存、取属性文件的内容,这先不表。
1、重点看下BeanFactoryPostProcessor的方法:
postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory){
Properties mergedProps = mergeProperties();{
if (localOverride){
//用localProperties覆盖properties文件中属性
}else{
//用properties文件属性覆盖localProperties
}
}
convertProperties(mergedProps); //无实际操作
processProperties(beanFactory, mergedProps);{
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver();
// beanFactory.resove.....()
}
}
2、再看它的属性:
PropertyPlaceHolderConfigurator{
locations; //配置文件地址
fileEncoding;
properties; //localProperties
localOverride; //properties覆盖方式
systemPropertiesMode; //与System.properties冲突怎么办:SYSTEM_PROPERTIES_MODE_FALLBACK
searchSystemEnvironment; //System.getEnv()
ignoreUnresolvablePlaceholders; //找不到某个属性
ignoreResourceNotFound; //找不到location
valueSeparator;
order;
propertiesPersister; //存/取对象
}
3、locations如何转换成Resources
DefaultResourceLoader.getResource(String location){
if (location.startsWith("/")) {
return getResourceByPath(location); //new ClassPathContextResource(path, getClassLoader())
}
else if (location.startsWith("classpath:")) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
return new UrlResource(new URL(location));
}
}
此外,针对classpath*: 》PathMatchingResourcePatternResolver.getResources();
4、如果要改造成一个ZK的configserver,使得server端提交的任意改动,都能立即更新到spring容器中,怎么办?
思路在于实现:ResourceLoader(locations)以及propertiesPreister。本人已经做到了。