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; }
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。