springboot中使用配置方式有四种,分别是environment、BeanDefinition、@Value、@ConfigurationProperties。具体的原理可以看我之前的一篇文章https://blog.csdn.net/cjc000/article/details/132800290。代码在https://gitee.com/summer-cat001/config-center
原理
environment是存储配置的地方,其他的都是从这里获取的数据。所以只要在他们用到配置之前,把配置放到environment中就可以了,先看下springboot的启动流程图。
可以看到业务代码第一次用到配置的地方是PropertySourcesPlaceholderConfigurer,它是一个BeanFactoryPostProcessor默认的order是最低优先级的,所以只要在执行它之前把配置放到environment对象中即可,如图标红的地方
不过很多三方的jar包可能会会自定义ApplicationContextInitializer和BeanFactoryPostProcessor。所以为了让这些jar包也用到我们的配置,所以要在更早的阶段加载配置,既然springboot提供了加载配置的扩展点,那我们直接注册一个自定义的EnvironmentPostProcessor类即可,不过因为我们加载配置的时候也要使用application.yml的配置,比如设置连接地址什么的,所以需要把我们的EnvironmentPostProcessor的优先级设置的小于ConfigDataEnvironmentPostProcessor,ConfigDataEnvironmentPostProcessor的优先级是Ordered.HIGHEST_PRECEDENCE + 10,我们只要把order设置成Ordered.HIGHEST_PRECEDENCE + 11即可
代码
ConfigCenterClient改为单例
private static volatile ConfigCenterClient client;private ConfigCenterClient(String url) {this.url = url;//将配置中心的配置转换成property格式,即user.name=xxxList<ConfigVO> configList = getAllValidConfig();this.configMap = configList2ConfigMap(configList);}public static ConfigCenterClient getInstance(String url) {return Optional.ofNullable(client).orElseGet(() -> {synchronized (ConfigCenterClient.class) {if (client == null) {client = new ConfigCenterClient(url);}return client;}});}
自定义EnvironmentPostProcessor
可以看到我们是从application.yml文件中获取了配置中心的地址,然后再把配置中心的配置注入到springboot中
public class ConfigEnvironmentPostProcessor implements EnvironmentPostProcessor {@Overridepublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {String configCenterUrl = environment.getProperty("config.center.url");ConfigCenterClient configCenterClient = ConfigCenterClient.getInstance(configCenterUrl);Map<String, Object> configProperty = configCenterClient.getConfigProperty();MutablePropertySources propertySources = environment.getPropertySources();MapPropertySource configCenter = new MapPropertySource("configCenter", configProperty);propertySources.addFirst(configCenter);}
}
注册EnvironmentPostProcessor
org.springframework.boot.env.EnvironmentPostProcessor=\
com.config.center.config.ConfigEnvironmentPostProcessor
效果
environment对象获取配置
@Autowiredprivate Environment environment;@Testpublic void configTest() {String userName = environment.getProperty("user.name");System.out.println(userName);}
xml中获取配置
public class User {private String userName;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-lazy-init="false"><bean id="user" class="com.config.center.test.User"><property name="userName" value="${user.name}"/></bean></beans>
@Value获取配置
@Value("${user.name}")private String name;@Testpublic void configTest() {System.out.println(name);}
@ConfigurationProperties
@Component
@ConfigurationProperties(prefix = "user")
public class UserConfig {private String name;private int age;private List<String> education;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public List<String> getEducation() {return education;}public void setEducation(List<String> education) {this.education = education;}
}
@Autowiredprivate UserConfig userConfig;@Testpublic void configTest() {System.out.println(userConfig);}