springboot-SPI-修改配置文件

1. 编写代码

package com.config;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.logging.DeferredLog;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

public class BootStrapConfigProcessor
        implements EnvironmentPostProcessor, ApplicationListener<ApplicationEvent>, Ordered {

    private static final DeferredLog LOGGER = new DeferredLog();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        if (application.getWebApplicationType() == WebApplicationType.SERVLET) {
            replaceConfig(environment, application);
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationPreparedEvent) {
            LOGGER.replayTo(BootStrapConfigProcessor.class);
        }
    }

    private void replaceConfig(ConfigurableEnvironment environment, SpringApplication application) {
        LOGGER.info("开始替换配置值===============");
        MutablePropertySources sources = environment.getPropertySources();
        Map<String, Object> newConfigMap = new HashMap<>();
        for (PropertySource<?> ps : sources) {
            if (!(ps instanceof OriginTrackedMapPropertySource)) {
                continue;
            }
            OriginTrackedMapPropertySource ops = (OriginTrackedMapPropertySource) ps;
            String[] names = ops.getPropertyNames();
            for (String name : names) {
                Object value = ops.getProperty(name);
                if (value instanceof String) {
                    LOGGER.info("原始配置:" + name + ":" + value);
                }
                // 替换新值
                if (Objects.equals("test.config.name", name)) {
                    newConfigMap.put(name, "newTestValue");
                    LOGGER.info("替换新的值:" + name + ": newTestValue");
                }
            }
        }
        newConfigMap.put("test.config.password", "password123");
        LOGGER.info("添加新值:test.config.password: password123");
        // 将新值注入配置中
        if (!newConfigMap.isEmpty()) {
            environment.getPropertySources()
                    .addFirst(new MapPropertySource("BootStrapConfigProcessor.properties", newConfigMap));
        }
        LOGGER.info("换值完毕===============");
    }

}

2.配置

resources/META-INF/spring.factories

# Environment Post Processor
org.springframework.boot.env.EnvironmentPostProcessor=
com.config.BootStrapConfigProcessor
org.springframework.context.ApplicationListener=
com.config.BootStrapConfigProcessor

3.业务使用

@Value("${test.config.name}")
private String testConfigName;
@Value("${test.config.password}")
private String testConfigPassword;

4. 备注

测试版本  2.3.4.RELEASE

5. 其他

由于这个类执行时日志系统还没有初始化所有使用了DeferredLog来打印日志,可是怎么都不输出日志

最后定位发现先是springboot热启动[restartedMain] RestartLauncher.java类加载器导致,将pom中的spring-boot-devtools依赖去掉问题解决