在SpringCloudAlibaba框架中,因Nacos配置中心管理权限过于简单,决定用Apollo代替Nacos配置中心,但在启动时,Nacos、Redis等配置读取正常,RocketMQ由于启动过早,无法从Apollo读取自己的服务地址配置。
报错如下:
Error processing condition on RocketMQAutoConfiguration.
针对此问题,进行以下3个方向的尝试,最开始觉得如果其他组件能正常读取Apollo配置,那应该是RocketMQ的问题,想办法降低它的加载顺序。最终发现不太现实,在RocketMQ社区也未找到相关问题。
尝试1.让rocketmq-spring-boot中的RocketMQAutoConfiguration延迟加载-失败
最起码要晚于ApolloAutoConfiguration。
如下方案失败:
/**
* 试图让RocketMQAutoConfiguration在ApolloAutoConfiguration之后加载
*/
@Configuration
@AutoConfigureBefore(RocketMQAutoConfiguration.class)
public class OrderConfiguration {
@Bean
@ConditionalOnMissingBean(ApolloAutoConfiguration.class)
public ApolloAutoConfiguration apolloAutoConfiguration() {
return new ApolloAutoConfiguration();
}
}
尝试2:开启全局懒加载,并排除Apollo-失败
尝试3:修改EnableApolloConfig order属性-失败
在启动类修改EnableApolloConfig order属性,还是报同样的错误。
@EnableApolloConfig(order = Integer.MIN VALUE)
解决方案:设置apollo更早阶段注入
直到忙活几个小时后,发现Apollo官方已经提供了容Apollo更早注入的方法,解决方法:
@SpringBootApplication
// 允许使用Feign客户端发送请求
@EnableFeignClients
// 指定要扫描的Mapper类的包的路径
@MapperScan("com.**.dao")
@EnableRedis
@EnableApolloConfig
// 扫描加载Filter
@ServletComponentScan
public class Application {
public static void main(String[] args) {
// 启用apollo配置开关 在应用启动阶段是否向Spring容器注入被托管的properties文件配置信息。
System.setProperty("apollo.bootstrap.enabled","true");
// 将Apollo配置加载提到初始化日志系统之前。
System.setProperty("apollo.bootstrap.eagerLoad.enabled","true");
SpringApplication.run(Application.class, args);
}
}
还有另一种方式:
Apollo官方文档
Apollo
Spring Boot除了支持上述两种集成方式以外,还支持通过application.properties/bootstrap.properties来配置,该方式能使配置在更早的阶段注入,比如使用@ConditionalOnProperty的场景或者是有一些spring-boot-starter在启动阶段就需要读取配置做一些事情(如dubbo-spring-boot-project),所以对于Spring Boot环境建议通过以下方式来接入Apollo(需要0.10.0及以上版本)。
从1.2.0版本开始,如果希望把日志相关的配置(如logging.level.root=info或logback-spring.xml中的参数)也放在Apollo管理,那么可以额外配置apollo.bootstrap.eagerLoad.enabled=true来使Apollo的加载顺序放到日志系统加载之前,不过这会导致Apollo的启动过程无法通过日志的方式输出(因为执行Apollo加载的时候,日志系统压根没有准备好呢!所以在Apollo代码中使用Slf4j的日志输出便没有任何内容),更多信息可以参考PR 1614。参考配置示例如下:
# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true
# put apollo initialization before logging system initialization
apollo.bootstrap.eagerLoad.enabled=true
因为搜索方向不对浪费了几个小时,一开始一直在搜索如何让RocketMQ加载晚于Apollo,重点在调整两者加载顺序上,后来又在研究RocketMQAutoConfiguration的加载原理,尝试各种方法让RMQ延迟加载,最后随便搜了一下Apollo加载顺序,答案其实很多,在解决问题时还是要多扩散一下思路。