1. Background
Apollo
Configuration Center was used in the previous project. After docking with the Apollo Configuration Center, the properties of the Configuration Center can be used in the program. So how is this achieved? When are the properties of the configuration center loaded into the program? So if we find out how this is implemented, can we 从任何地方加载配置属性
, 配置属性的加解密功能呢
?
2. Demand
从上图中得知,我们的需求很简单,即我们自己定义的属性需要比配置文件中的优先级更高。
3. Analysis
1. When to add our own configuration properties to SpringBoot
When we want to use configuration properties in beans, then our configuration properties must be put into Spring to Environment before the bean is instantiated. That is, our interface needs to be called before application context refreshed
, and EnvironmentPostProcessor
can just achieve this function.
2. Get the priority of configuration properties
We know that getting properties in Spring has priority.
For example, we have the following configuration properties username
├─application.properties
│ >> username=huan
├─application-dev.properties
│ >> username=huan.fu
So what is the value of username
at this time? Here is a picture of Apollo
to explain this problem.
Reference link: https://www.apolloconfig.com/#/zh/design/apollo-design
Spring has added ConfigurableEnvironment
and PropertySource
since version 3.1:
ConfigurableEnvironment
- Spring's ApplicationContext will contain an Environment (implementing the ConfigurableEnvironment interface)
- ConfigurableEnvironment itself contains many PropertySource
PropertySource
- property source
- It can be understood as the property configuration of many Key-Value
From the diagram above, key
most began to appear PropertySource
higher priority in the above example in SpringBoot
in username
The value of username
is huan.fu
.
3. When to add our own configuration
From the second step 获取配置属性的优先级
, we can see that PropertySource
is executed first, so for our configuration to take effect, it must be placed as far ahead as possible.
As can be seen from the above figure, SpringBoot loads various configurations through EnvironmentPostProcessor
to achieve, and the specific implementation is ConfigDataEnvironmentPostProcessor
to achieve. Then we write an implementation class of EnvironmentPostProcessor
cad11a75de97d59ff64f4474432d9028---, and then execute it after ConfigDataEnvironmentPostProcessor
, and add it to the first place in Environment
.
4. Realization
1. Introduce SpringBoot dependencies
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.huan.springcloud</groupId>
<artifactId>springboot-extension-point</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-extension-point</name>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
2. Configure properties in application.properties
vim application.properties
username=huan
3. Write custom properties and add them to Spring Environment
Notice:
1. If it is found that the log in the program is not output, check whether slf4j
is used to output the log. At this time, the log cannot be output because the log system is not initialized. 解决方法如下:
SpringBoot版本
>= 2.4 可以参考上图中的使用 DeferredLogFactory 来输出日志
< 2.4
1、参考如下链接 https://stackoverflow.com/questions/42839798/how-to-log-errors-in-a-environmentpostprocessor-execution
2、核心代码:
@Component
public class MyEnvironmentPostProcessor implements
EnvironmentPostProcessor, ApplicationListener<ApplicationEvent> {
private static final DeferredLog log = new DeferredLog();
@Override
public void postProcessEnvironment(
ConfigurableEnvironment env, SpringApplication app) {
log.error("This should be printed");
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
log.replayTo(MyEnvironmentPostProcessor.class);
}
}
4. Make the custom configuration take effect through SPI
1. Create a new file under src/main/resources
META-INF/spring.factories
2. Configuration
org.springframework.boot.env.EnvironmentPostProcessor=\
com.huan.springcloud.extensionpoint.environmentpostprocessor.CustomEnvironmentPostProcessor
5. Write a test class and output the value of the defined username attribute
@Component
public class PrintCustomizeEnvironmentProperty implements ApplicationRunner {
private static final Logger log = LoggerFactory.getLogger(PrintCustomizeEnvironmentProperty.class);
@Value("${username}")
private String userName;
@Override
public void run(ApplicationArguments args) {
log.info("获取到的 username 的属性值为: {}", userName);
}
}
6. Running results
Five, matters needing attention
1. The log cannot be output
Refer to the solution provided above 3、编写自定义属性并加入Spring Environment中
.
2. The configuration does not take effect
- Check the priority of
EnvironmentPostProcessor
to see if@Order
orOrdered
returns the wrong priority value. - See if it is implemented elsewhere
EnvironmentPostProcessor
orApplicationContextInitializer
orBeanFactoryPostProcessor
orBeanDefinitionRegistryPostProcessor
etcPropertySource
The order ofPropertySource
. - Understanding the order in which Spring gets properties is referenced
2、获取配置属性的优先级
3. How to initialize the log system
The following code initializes the logging system
org.springframework.boot.context.logging.LoggingApplicationListener
6. Complete code
7. Reference link
1. https://github.com/apolloconfig/apollo/blob/master/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java
2. https://github.com/apolloconfig/apollo/blob/master/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java
3. https://www.apolloconfig.com/#/zh/design/apollo-design
4. Solve the problem that the log cannot be output in EnvironmentPostProcessor
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。