spring cloud项目中,在bootstrap.yml中指定了active的profile,结果不生效
问题描述#接手的一个spring cloud项目我最近在对其进行改造更符合自己的习惯。我个人习惯在bootsrap.yml中指定spring.profiles.active如下所示只要修改spring.profiles.active的值就能切换到想要的profile去使用对应的nacos配置spring: application: name: demo-svc profiles: active: dev --- spring: config: activate: on-profile: dev cloud: nacos: config: username: xxx password: xxxx enabled: false file-extension: yaml #文件扩展名 server-addr: 1.1.1.1:8848 namespace: 148586df-f999-4f83-a2fe-39b9add32196 --- spring: config: activate: on-profile: test cloud: nacos: config: username: xxx password: xxxx enabled: true file-extension: yaml #文件扩展名 server-addr: 1.1.1.1:8848 namespace: dfcf830b-0cd3-433b-bf35-6d153b9f142d当然上面文件中的profile为dev我们还可以在命令行启动脚本中指定(java -Dspring.profiles.activeprod -jar demo.jar)命令行中优先级最高此时profile就是prod。当然命令行中不指定时就应该是bootsrap.yml中的为准。我这次问题就是发生在命令行未指定的情况下bootstrap.yml中指定了dev这个profile。下图我这里并未启用nacos此时按理说就会去找application-dev.yml这个配置最终却好像是没去读取application-dev.yml导致程序读取不到配置直接启动失败了。但是我发现服务器上运行时我们都是在命令行中指定了profile运行是完全正常的java -Dspring.profiles.activedev -jar demo.jar为啥不在命令行中指定就不行呢在本地idea中启动我都是不会加命令行参数的按理说就会取bootstrap.yml中的profile框架版本spring-boot基本是2.7.*中的最高版本了cloud版本是2021.0.5。properties java.version1.8/java.version spring-boot.version2.7.16/spring-boot.version spring-cloud-alibaba.version2021.0.5.0/spring-cloud-alibaba.version spring-cloud.version2021.0.5/spring-cloud.version /properties简略排查过程#正常和异常情况下的对比#由于可以复现且在本地可以debug而且可以对比正常和异常时的情况这个问题肯定是能找到的。我发现正常情况下本地idea启动时指定下命令行参数在查找配置值时一般就是去Environment中的propertySource列表中查找正常长这样上图所示是有一个classpath下的resourceapplication-dev.yml。这个propertySource的类型是com.ulisesbocchio.jasyptspringboot.wrapper.EncryptableMapPropertySourceWrapper大家可能有点奇怪不熟悉这个类这个是因为我们项目在生产环境里对配置文件中的值进行了加密比如数据库密码。这个加解密用的是dependency groupIdcom.github.ulisesbocchio/groupId artifactIdjasypt-spring-boot-starter/artifactId version3.0.4/version /dependency本来正常情况下propertySource的类型大概是这样然后jasypt这个加解密组件就把上述的propertySource类型全给转成了它自己的EncryptableMapPropertySourceWrapper然后内部再包含了原始的propertySourcedebug发现EncryptableMapPropertySourceWrapper中包含的原始的propertySource类型为org.springframework.boot.env.OriginTrackedMapPropertySourceOriginTrackedMapPropertySource初始化#我们接下来看看正常情况下OriginTrackedMapPropertySource是啥时候初始化的。打个断点最后发现new的时机大概是applicationContext这个上下文完成了environmentPrepared后就会发布一个org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent这时候各个listener就会处理这个事件。其中一个listener为org.springframework.boot.env.EnvironmentPostProcessorApplicationListener这个listener中会找到各个EnvironmentPostProcessor这个后置处理器接口类似于bean的那些后置处理器也是spring给我们提供的扩展点这个org.springframework.boot.env.EnvironmentPostProcessor主要就是方便我们对Environment进行后置处理。在我这边找到的Environment后置处理器还是很多其中的第7个ConfigDataEnvironmentPostProcessor就是本文主角它就会到处去找配置如果想要完整了解这块的流程可以打开logger配置logger nameorg.springframework.boot.context.config levelTRACE/ logger nameorg.springframework.boot.logging levelTRACE/大概流程如下查找的位置04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataEnvironment Adding initial config data import from location optional:file:./;optional:file:./config/;optional:file:./config/*/ [DeferredLog.java:249] 04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataEnvironment Adding initial config data import from location optional:classpath:/;optional:classpath:/config/ [DeferredLog.java:249]查找的文件04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./application.yaml [DeferredLog.java:249] 04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./application.yml [DeferredLog.java:249] 04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./application.properties [DeferredLog.java:249] 04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./application.json [DeferredLog.java:249] 04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./application.xml [DeferredLog.java:249] 04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/application.yaml [DeferredLog.java:249] 04-26 15:30:47.949 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/application.yml [DeferredLog.java:249] 04-26 15:30:47.954 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/application.properties [DeferredLog.java:249] 04-26 15:30:47.954 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/application.json [DeferredLog.java:249] 04-26 15:30:47.954 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/application.xml [DeferredLog.java:249]在计算了profile后如profile为dev则问题原因#后来经过反复对比正常和异常情况下的代码路径发现异常情况下计算出来的active的profile竟然是空的。正常情况下profile是dev。然后重点查下面的代码Environment获取profile为啥是null#我们知道在environment中包含了propertySource的list我在对比异常情况下的list发现如下的propertySource有差别正常情况下我这边profile是在bootstrap.yml这种指定的那就应该正常如下上图中names这个数组里包含了两个bootstrap.yml其实就是如下这两段配置但是在异常情况下names数组是空的切到这个propertySource的代码一看找了下操作names数组的地方发现会判断propertySource是不是OriginTrackedMapPropertySource类型而我们知道的是那个加密组件会把正常的OriginTrackedMapPropertySource类型的propertySource转成EncryptableMapPropertySourceWrapper而这个EncryptableMapPropertySourceWrapper就不是OriginTrackedMapPropertySource的子类所以这里就没法加入到names数组。修改方式#我以前就被这个加密组件坑过一次了改的方式就是直接把这个类的源码拷贝了一份改了一下放到项目的src下包名不能变add方法的调用时机#上述这个方法什么时候调用的呢其实就是在上文说的applicationContext这个上下文完成了environmentPrepared后就会发布一个org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent这时候各个listener就会处理这个事件。前面那个listener是下图第3个这里我们add方法这块就是在第一个listener中调用的org.springframework.cloud.bootstrap.BootstrapApplicationListener这个listener就负责了spring cloud中boostrap阶段的工作支持bootstrap.yml从nacos这类配置中心读取配置。在这个listener中下图所示这个listener中也会生成一个bootstrap阶段的applicationContext且也会查找自己的各个propertySource作为自己的env包括去查找各个bootstrap.yml等配置文件04-26 15:55:39.725 [main] TRACE [] o.s.b.c.config.ConfigDataEnvironmentContributors Processing imports [optional:file:./;optional:file:./config/;optional:file:./config/*/] [DeferredLog.java:249] 04-26 15:55:39.725 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./bootstrap.yaml [DeferredLog.java:249] 04-26 15:55:39.725 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./bootstrap.yml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./bootstrap.properties [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./bootstrap.json [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./bootstrap.xml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/bootstrap.yaml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/bootstrap.yml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/bootstrap.properties [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/bootstrap.json [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource file:./config/bootstrap.xml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataImporter Considering resource file [.] from location optional:file:./;optional:file:./config/;optional:file:./config/*/ [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLoaders Loading file [.] using loader org.springframework.boot.context.config.StandardConfigDataLoader [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataImporter Loaded resource file [.] from location optional:file:./;optional:file:./config/;optional:file:./config/*/ [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.b.c.config.ConfigDataEnvironmentContributors Imported 1 resource [file [.]] [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.b.c.config.ConfigDataEnvironmentContributors Processing imports [optional:classpath:/;optional:classpath:/config/] [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/bootstrap.yaml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/bootstrap.properties [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/bootstrap.json [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/bootstrap.xml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/config/bootstrap.yaml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/config/bootstrap.yml [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/config/bootstrap.properties [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/config/bootstrap.json [DeferredLog.java:249] 04-26 15:55:39.726 [main] TRACE [] o.s.boot.context.config.ConfigDataLocationResolver Skipping missing resource classpath:/config/bootstrap.xml [DeferredLog.java:249]最终bootstrap阶段这些配置是需要合并到原来的env里的。下图就是触发add方法的地方就是需要修改代码的那里