6 Star 72 Fork 28

JustryDeng / notebook

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
[07]利用EnvironmentPostProcessor动态修改配置.md 6.89 KB
一键复制 编辑 原始数据 按行查看 历史
邓沙利文 提交于 2022-08-03 17:43 . 优化author

利用EnvironmentPostProcessor动态修改配置

利用EnvironmentPostProcessor动态修改配置

第一步:编写EnvironmentPostProcessor

可以不需要使用@Configuration之类的注解的;这里加上,是因为本人想在容器启动后利用ApplicationRunner打印出一些日志信息,以便观察

postProcessEnvironment方法的执行时机早于日志框架的加载,所以在postProcessEnvironment方法里面是打不出来日志的

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.commons.util.InetUtilsProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;

import javax.annotation.Resource;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 动态修改 配置文件内容
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2022/7/7 15:07
 */
@Slf4j
@Configuration
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor, ApplicationRunner {
    
    private static final List<String> TIPS = new CopyOnWriteArrayList<>();
    
    /**
     * 要替代的key
     */
    String targetKey = "xxl.job.executor.ip";
    
    @Resource
    private Environment environment;
    
    @Override
    @SuppressWarnings("AlibabaRemoveCommentedCode")
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        MutablePropertySources propertySources = environment.getPropertySources();
        
        for (PropertySource<?> propertySource : propertySources) {
            if (propertySource.containsProperty(targetKey)) {
                String tips = String.format("#postProcessEnvironment exist k-v '%s=%s' in inetUtilsProperties '%s'", targetKey,
                        propertySource.getProperty(targetKey),
                        propertySource.getName());
                System.out.println(tips);
                TIPS.add(tips);
            }
        }
        /*
         * 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
         *
         *      1、引入依赖:
         *          <dependency>
         *             <groupId>org.springframework.cloud</groupId>
         *             <artifactId>spring-cloud-commons</artifactId>
         *             <version>${version}</version>
         *         </dependency>
         *
         *      2、设置首选网络 (
         *                      1. 可以在配置文件中配置,然后可以@Autowired自动装配InetUtilsProperties对象
         *                      2. 也可以new InetUtilsProperties()对象,主动调用相关设置方法进行设置
         *                     )
         *          spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
         *
         *      3、获取IP (需要借助于InetUtilsProperties实例, )
         *          String ip = new InetUtils(inetUtilsProperties).findFirstNonLoopbackHostInfo().getIpAddress();
         */
        InetUtilsProperties inetUtilsProperties = new InetUtilsProperties();
        // 设置忽略的网卡(支持正则) 网卡一般以eth、em之类的打头
        inetUtilsProperties.setIgnoredInterfaces(Lists.newArrayList("eth0"));
        /*
         * 设置首选网卡(支持正则)
         * 注:参数是一个list; 当InetUtils找到第一个满足list里面一个(或多个)匹配的ip时,就会返回这个ip. 即:首选项匹配与list中元素的先后无关, 凡是list的,都被认为是首选项,没有谁更首选的说法
         */
        inetUtilsProperties.setPreferredNetworks(Lists.newArrayList("192\\.*"));
        String ipAddress = new InetUtils(inetUtilsProperties).findFirstNonLoopbackHostInfo().getIpAddress();
        String tips = String.format("#postProcessEnvironment custom k-v '%s=%s'", targetKey, ipAddress);
        System.out.println(tips);
        TIPS.add(tips);
        
        Properties customProperties = new Properties();
        customProperties.put(targetKey, ipAddress);
        PropertiesPropertySource propertiesPropertySource = new PropertiesPropertySource("customProperties",
                customProperties);
        /*
         * 你可以使用propertySources.replace()直接用新的代替旧的;
         * 也可以保留原来的,同时将自定义的配置的优先级调高一点(如果有相同的key,那么越在propertySources前面的,优先级越高,就会使用优先级高的那个key对应的值; 这里addFirst,即表示优先级最高)
         */
        propertySources.addFirst(propertiesPropertySource);
    }
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        for (String tips : TIPS) {
            log.info("CustomEnvironmentPostProcessor | " + tips);
        }
        log.info("CustomEnvironmentPostProcessor | curr {}={}", targetKey, environment.getProperty(targetKey));
    }
}

第二步:配置spring.factories

/resources/META-INF/目录下的spring.factories文件(无则创建)中,指明环境后处理器

org.springframework.boot.env.EnvironmentPostProcessor=com.example.springbootdemo.CustomEnvironmentPostProcessor

注:多个使用逗号分割,如:

org.springframework.boot.env.EnvironmentPostProcessor=com.example.springbootdemo.CustomEnvironmentPostProcessor1,com.example.springbootdemo.CustomEnvironmentPostProcessor2

如果你要换行的话:

org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.springbootdemo.CustomEnvironmentPostProcessor1,\
com.example.springbootdemo.CustomEnvironmentPostProcessor2

测试一下

启动项目,观察到控制台日志

1657182474326

1
https://gitee.com/JustryDeng/notebook.git
git@gitee.com:JustryDeng/notebook.git
JustryDeng
notebook
notebook
master

搜索帮助