由于需要加载一些自定义文件,所以就自定义了一个类然后实现了EnvironmentPostProcessor接口
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {
/**
* 自定义配置文件
*/
private final String[] profiles = SystemConstant.CUSTOM_PROPS_FILE_NAME.split(",");
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
System.out.println("-----load custom resource file-------");
//循环添加
for (String profile : profiles) {
//从classpath路径下面查找文件
Resource resource = new ClassPathResource(profile);
//加载成PropertySource对象,并添加到Environment环境中
PropertySource<?> propertySource = loadProfiles(resource);
if(Objects.nonNull(propertySource)) {
environment.getPropertySources().addLast(propertySource);
}
}
}
//加载单个配置文件
private PropertySource<?> loadProfiles(Resource resource) {
if (!resource.exists()) {
throw new IllegalArgumentException("资源文件 " + resource + " 不存在");
}
try {
String sourceName = resource.getFilename();
// 对自定义yml配置文件加载
YmlResourceFactory ymlResourceFactory = new YmlResourceFactory();
return ymlResourceFactory.createPropertySource(sourceName,new EncodedResource(resource));
}catch (IOException ex) {
throw new IllegalStateException("加载配置文件失败" + resource, ex);
}
}
}
然后在resource下配置了META_INF,spring.factories
org.springframework.boot.env.EnvironmentPostProcessor=\
com.cpms.auth.config.MyEnvironmentPostProcessor
网上都是这么配置了,我不知道其它人有没有同样的问题,就是在启动服务的时候,重写了postProcessEnvironment方法执行了两次
因为控制台输出了两次打印
System.out.println("-----load custom resource file-------");
(°ー°〃)相信如果没有比较手癌的在另一个地方写了另一个
EnvironmentPostProcessor
的实现类,恰好也是同一个System.out.println
的话,那我估计可能跟Spring Cloud
有点关系当然我这是比较大胆的猜测哈,毕竟题主在问题中没有任何提到跟
Spring Cloud
有关系,没准我这只是提供一个思路,因为Spring Cloud
可能会导致下面说的原因,但也许也不是Spring Cloud
,或者是题主公司内部自我的实现,但是他们的原因是一致,题主可以根据实际情况实际排查原因即为:项目中存在两个
ApplicationContext
(两个之间可能有父子关系也可能没关系这里解释一下,因为
EnvironmentPostProcessor
的触发是基于EnvironmentPostProcessorApplicationListener
中对于ApplicationEnvironmentPreparedEvent
事件的响应而
ApplicationEnvironmentPreparedEvent
这个事件,从名字来看,他就是基于Environment
也就是我们常使用的配置文件的相关流程(这里指Prepared
预准备流程)的事件恰好,我们知道
ApplicationContext
的创建就是基于配置文件(注解形式也算是一种配置文件),也就是基于Environment
的因此要是题主的代码中有两个
ApplicationContext
,那MyEnvironmentPostProcessor
就一定会调用两次了这里为啥之前我猜测说跟
Spring Cloud
有关,就是因为我记得以前整Spring Cloud
的时候,是有一个配置文件的配置文件说法的,也就是还有一个可以配置application.yml
文件中的变量的配置文件bootstrap.yml
,这样的boot
是有两个ApplicationContext
的其中由
bootstrap.yml
创建出来的ApplicationContext
是父由
application.yml
创建的ApplicationContext
是子虽然它们的
Environment
不同,但application.yml
所属的Environment
是包含了bootstrap.yml
中的配置信息的。详见AbstractApplicationContext.setParent
所以我才说可能和
Spring Cloud
有关,当然还是不排除公司内部自己实现的另一个ApplicationContext
,题主可以自行排查至于最后如何解决这个问题
1.如果是恰好用的
Spring Cloud
那其实没啥问题的,可以啥都不改,因为虽然进入了两次
MyEnvironmentPostProcessor
,但是它们都对应的是不同的Environment
和不同的SpringApplication
,虽然最后两个Environment
都加载了相同的自定义配置文件,如果不影响你的业务,其实也没啥太大问题。如果非要说,只在application.yml
所属的Environment
加载的话,那可以去根据SpringApplication
做一个区分,利用setEnvironmentPrefix
方法,因为bootstrap.yml
的SpringApplication
的getEnvironmentPrefix
返回是null
的然后你就可以在你的
MyEnvironmentPostProcessor
中根据EnvironmentPrefix
去做逻辑处理了2.如果不是类似
Spring Cloud
,完全是公司内部自定义的ApplicationContext
由于信息不多,那就只有题主自行结合我的思路去看看了
总之大致我的想法就是这样的叭,希望能对你有所帮助╰(°▽°)╯