欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring boot外部配置(配置中心化)详解

程序员文章站 2023-12-02 19:45:16
前言 在项目中为了灵活配置,我们常采用配置文件,常见的配置文件就比如xml和properties,springboot允许使用properties和yaml文件作为外部配...

前言

在项目中为了灵活配置,我们常采用配置文件,常见的配置文件就比如xml和properties,springboot允许使用properties和yaml文件作为外部配置。现在编译器对于yaml语言的支持还不够好,目前还是使用properties文件作为外部配置。

在spring cloud config出来之前, 自己实现了基于zk的配置中心, 杜绝了本地properties配置文件, 原理很简单, 只是重载了propertyplaceholderconfigurer的mergeproperties() :

/**
 * 重载合并属性实现
 * 先加载file properties, 然后并入zk配置中心读取的properties
 *
 * @return 合并后的属性集合
 * @throws ioexception 异常
 */
@override
protected properties mergeproperties() throws ioexception {
 properties result = new properties();
 // 加载父类的配置
 properties mergeproperties = super.mergeproperties();
 result.putall(mergeproperties);
 // 加载从zk中读取到的配置
 map<string, string> configs = loadzkconfigs();
 result.putall(configs);
 return result;
}

这个实现在spring项目里用起来还是挺顺手的, 但是近期部分spring-boot项目里发现这种placeholder的实现跟spring boot的@configurationproperties(prefix = "xxx") 不能很好的配合工作,

也就是属性没有被resolve处理, 用@value的方式确可以读到, 但是@value配置起来如果属性多的话还是挺繁琐的, 还是倾向用@configurationproperties的prefix, 于是看了下spring boot的文档发现 propertysource

order:

* devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).

* @testpropertysource annotations on your tests.

* @springboottest#properties annotation attribute on your tests.

* command line arguments.

* properties from spring_application_json (inline json embedded in an environment variable or system property)

* servletconfig init parameters.

* servletcontext init parameters.

* jndi attributes from java:comp/env.

* java system properties (system.getproperties()).

* os environment variables.

* a randomvaluepropertysource that only has properties in random.*.

* profile-specific application properties outside of your packaged jar (application-{profile}.properties and yaml variants)

* profile-specific application properties packaged inside your jar (application-{profile}.properties and yaml variants)

* application properties outside of your packaged jar (application.properties and yaml variants).

* application properties packaged inside your jar (application.properties and yaml variants).

* @propertysource annotations on your @configuration classes.

* default properties (specified using springapplication.setdefaultproperties).

不难发现其会检查java system propeties里的属性, 也就是说, 只要把mergerproperties读到的属性写入java system props里即可, 看了下源码, 找到个切入点

/**
 * 重载处理属性实现
 * 根据选项, 决定是否将合并后的props写入系统属性, spring boot需要
 *
 * @param beanfactorytoprocess
 * @param props    合并后的属性
 * @throws beansexception
 */
@override
protected void processproperties(configurablelistablebeanfactory beanfactorytoprocess, properties props) throws beansexception {
 // 原有逻辑
  super.processproperties(beanfactorytoprocess, props);
 // 写入到系统属性
 if (writepropstosystem) {
  // write all properties to system for spring boot
  enumeration<?> propertynames = props.propertynames();
  while (propertynames.hasmoreelements()) {
    string propertyname = (string) propertynames.nextelement();
    string propertyvalue = props.getproperty(propertyname);
    system.setproperty(propertyname, propertyvalue);
  }
 }
}

为避免影响过大, 设置了个开关, 是否写入系统属性, 如果是spring boot的项目, 就开启, 这样对线上非spring boot项目做到影响最小, 然后spring boot的@configurationproperties完美读到属性;

具体代码见: org.springframework.boot.context.properties.configurationpropertiesbindingpostprocessor

@override
public object postprocessbeforeinitialization(object bean, string beanname)
  throws beansexception {
 configurationproperties annotation = 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);
 }
 return bean;
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。