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=xxx
List<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 {
@Override
public 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对象获取配置
@Autowired
private Environment environment;
@Test
public 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;
@Test
public 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;
}
}
@Autowired
private UserConfig userConfig;
@Test
public void configTest() {
System.out.println(userConfig);
}