springboot 自定义listener 添加环境变量。 抄的springboot项目去掉了一些不用的jar包后包 No Value Bound 错误排查。

发布时间 2023-06-15 14:26:23作者: 远方的人

1. 自定义listener 实现 ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered (如果要设置优先级可以实现Ordered接口,注意order值越小优先级越高)

public class MyListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        Map<String, Object> bootstrapMap = new HashMap<>();
        bootstrapMap.put("spring.config.name", "bootstrap");
        event.getEnvironment().getPropertySources().addLast(new MapPropertySource("bootstrap", bootstrapMap));
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 1;
    }
}

2. 启动类 addListener(new MyListener()) 即可。

 

问题: 抄的springboot项目去掉了一些不用的jar包后包 No Value Bound 错误排查。

看错误: No Value Bound , 具体没截图,发现是spring.dataousrce.xx 参数没有读取到。检查项目配置及apollo 没有问题。 

查看debug日志,发现读取了另外一个项目的配置,项目名yy,全局搜索关于yy的配置文件,在一个jar包中找到application.properties 。 

本项目有配置文件,名为 bootstrap.yml 。为什么原项目会读取bootstrap.yml作为项目配置,而新项目则是已application.properties 为项目配置。 

grpc:
  server:
    port: 8080

spring:
  application:
    name: xx   (application.properties 中该项为 yy)
  profiles:
    active: dev

debug代码发现 ConfigFileApplicationListener 读取配置文件: 

private Set<String> getSearchNames() {
			if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {
				String property = this.environment.getProperty(CONFIG_NAME_PROPERTY);
				return asResolvedSet(property, null);
			}
			return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);
		} 

其中 CONFIG_NAME_PROPERTY = spring.config.name  如果环境变量中有配置,则优先使用该名称读取配置文件,否则默认为 application。 

扩展1:配置文件路径的优先级问题

// Note the order is from least to most specific (last one wins)private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";

扩展2:不仅可以指定配置文件名,还能指定路径。

The 'spring.config.name' property can be used to specify an alternative name to load
* and the 'spring.config.location' property can be used to specify alternative search
* locations or specific files.

应该是老项目指定了spring.config.name , 发现老项目引入了springcloud, 定义了BootstrapApplicationListener 。