Spring boot外部配置(配置中心化)详解
前言
在项目中为了灵活配置,我们常采用配置文件,常见的配置文件就比如xml和properties,springboot允许使用properties和yaml文件作为外部配置。现在编译器对于yaml语言的支持还不够好,目前还是使用properties文件作为外部配置。
在Springcloudconfig出来之前,自己实现了基于ZK的配置中心,杜绝了本地properties配置文件,原理很简单,只是重载了PropertyPlaceholderConfigurer的mergeProperties():
/**
*重载合并属性实现
*先加载fileproperties,然后并入ZK配置中心读取的properties
*
*@return合并后的属性集合
*@throwsIOException异常
*/
@Override
protectedPropertiesmergeProperties()throwsIOException{
Propertiesresult=newProperties();
//加载父类的配置
PropertiesmergeProperties=super.mergeProperties();
result.putAll(mergeProperties);
//加载从zk中读取到的配置
Mapconfigs=loadZkConfigs();
result.putAll(configs);
returnresult;
}
这个实现在spring项目里用起来还是挺顺手的,但是近期部分spring-boot项目里发现这种placeholder的实现跟springboot的@ConfigurationProperties(prefix="xxx")不能很好的配合工作,
也就是属性没有被resolve处理,用@Value的方式确可以读到,但是@Value配置起来如果属性多的话还是挺繁琐的,还是倾向用@ConfigurationProperties的prefix,于是看了下springboot的文档发现PropertySource
order:
*Devtoolsglobalsettingspropertiesonyourhomedirectory(~/.spring-boot-devtools.propertieswhendevtoolsisactive).
*@TestPropertySourceannotationsonyourtests.
*@SpringBootTest#propertiesannotationattributeonyourtests.
*Commandlinearguments.
*PropertiesfromSPRING_APPLICATION_JSON(inlineJSONembeddedinanenvironmentvariableorsystemproperty)
*ServletConfiginitparameters.
*ServletContextinitparameters.
*JNDIattributesfromjava:comp/env.
*JavaSystemproperties(System.getProperties()).
*OSenvironmentvariables.
*ARandomValuePropertySourcethatonlyhaspropertiesinrandom.*.
*Profile-specificapplicationpropertiesoutsideofyourpackagedjar(application-{profile}.propertiesandYAMLvariants)
*Profile-specificapplicationpropertiespackagedinsideyourjar(application-{profile}.propertiesandYAMLvariants)
*Applicationpropertiesoutsideofyourpackagedjar(application.propertiesandYAMLvariants).
*Applicationpropertiespackagedinsideyourjar(application.propertiesandYAMLvariants).
*@PropertySourceannotationsonyour@Configurationclasses.
*Defaultproperties(specifiedusingSpringApplication.setDefaultProperties).
不难发现其会检查Javasystempropeties里的属性,也就是说,只要把mergerProperties读到的属性写入Javasystemprops里即可,看了下源码,找到个切入点
/**
*重载处理属性实现
*根据选项,决定是否将合并后的props写入系统属性,Springboot需要
*
*@parambeanFactoryToProcess
*@paramprops合并后的属性
*@throwsBeansException
*/
@Override
protectedvoidprocessProperties(ConfigurableListableBeanFactorybeanFactoryToProcess,Propertiesprops)throwsBeansException{
//原有逻辑
super.processProperties(beanFactoryToProcess,props);
//写入到系统属性
if(writePropsToSystem){
//writeallpropertiestosystemforspringboot
Enumeration>propertyNames=props.propertyNames();
while(propertyNames.hasMoreElements()){
StringpropertyName=(String)propertyNames.nextElement();
StringpropertyValue=props.getProperty(propertyName);
System.setProperty(propertyName,propertyValue);
}
}
}
为避免影响过大,设置了个开关,是否写入系统属性,如果是springboot的项目,就开启,这样对线上非springboot项目做到影响最小,然后springboot的@ConfigurationProperties完美读到属性;
具体代码见:org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
@Override
publicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)
throwsBeansException{
ConfigurationPropertiesannotation=AnnotationUtils
.findAnnotation(bean.getClass(),ConfigurationProperties.class);
if(annotation!=null){
postProcessBeforeInitialization(bean,beanName,annotation);
}
annotation=this.beans.findFactoryAnnotation(beanName,
ConfigurationProperties.class);
if(annotation!=null){
postProcessBeforeInitialization(bean,beanName,annotation);
}
returnbean;
}
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。