为什么要用 ApplicationReadyEvent 来初始化 RabbitTemplate 回调?
文章目录一、结论先行二、ApplicationReadyEvent 到底是什么三、Spring Boot 启动生命周期四、你在做什么为什么这件事对时机敏感五、为什么不能随便写在 PostConstruct 里六、为什么 ApplicationReadyEvent 是“黄金时间点”七、用生活比喻八、几种常见初始化方式对比九、更推荐的工程写法两种十、总结很多时候看到下面这行代码会懵publicclassRabbitInitConfigApplicationListenerimplementsApplicationListenerApplicationReadyEvent看起来只是“监听一个事件”但它背后体现的是Spring Boot 生命周期理解与RabbitTemplate 初始化时机控制。ApplicationReadyEvent到底是什么为什么不能随便在PostConstruct里 setConfirmCallbackRabbitTemplate 的自动配置顺序是怎样的常见坑有哪些推荐的工程写法是什么一、结论先行implements ApplicationListenerApplicationReadyEvent的意思是等 Spring Boot 应用完全启动之后再执行初始化逻辑。也就是等所有 Bean 自动配置都完成之后再给 RabbitTemplate 设置回调。这种写法的核心价值是避免初始化太早被覆盖 / 无效 / 不稳定。二、ApplicationReadyEvent 到底是什么Spring Boot 启动过程中会发布多个事件常见的包括ApplicationStartingEventApplicationEnvironmentPreparedEventApplicationPreparedEventContextRefreshedEventApplicationStartedEvent✅ApplicationReadyEvent最晚、最稳你可以把它理解成“应用已经能对外提供服务了”当ApplicationReadyEvent发布时一般意味着Spring 容器已经刷新完成所有 Bean 都初始化完了CommandLineRunner / ApplicationRunner 都已经执行完Web 容器如 Tomcat已经启动并监听端口应用已经 ready可以接请求 所以它是一个“非常稳妥的初始化时机”。三、Spring Boot 启动生命周期为了准确理解“为什么必须等到 ready”我们把启动流程拆得更细一点1) 读取 application.yml / application.properties 2) 创建 ApplicationContext容器 3) 扫描配置类SpringBootApplication / Configuration 4) 开始自动配置AutoConfiguration 生效 5) 注册 BeanDefinition 6) 创建 Bean 实例构造方法 7) 依赖注入Autowired 8) Bean 初始化回调 - PostConstruct - InitializingBean.afterPropertiesSet - 自定义 init-method 9) Context refresh 完成 10) 执行 Runner - CommandLineRunner - ApplicationRunner 11) 启动 Web ServerTomcat/Netty 12) 发布 ApplicationReadyEvent ✅ 最终阶段关键点Spring Boot 的“自动配置”可能在你之后继续修改某些 Bean这就是为什么“太早 setCallback” 会被覆盖。四、你在做什么为什么这件事对时机敏感你在做的是rabbitTemplate.setConfirmCallback(...)rabbitTemplate.setReturnsCallback(...)这属于✅修改 RabbitTemplate 的全局行为它不是“普通字段赋值”而是改变整个 MQ 投递链路的回调策略。这种全局行为配置非常怕两件事RabbitTemplate 还没完全初始化好RabbitTemplate 后续还会被 Spring Boot 自动配置“再加工”五、为什么不能随便写在 PostConstruct 里很多人第一反应是“我在 Bean 初始化完之后 setCallback不就行了吗”比如PostConstructpublicvoidinit(){rabbitTemplate.setConfirmCallback(...);}❌ 这可能会出的问题真实项目常见回调被覆盖最常见RabbitTemplate 是 Spring Boot 自动配置出来的组件它可能在后续自动配置阶段继续设置默认属性。你在PostConstruct设置回调后PostConstruct 执行你 setCallback ↓ 后续某个 AutoConfiguration 执行重新 setCallback ↓ 你的回调失效你还以为生效了这种问题的特点是不报错只是“回调没触发”非常难排查多个 RabbitTemplate / 多个 ConnectionFactory 时混乱如果项目后来引入多数据源 RabbitMQ多个 RabbitTemplate或者框架自动注册了另一个 template你早期 set 的可能不是最终用于发送消息的那个 template。六、为什么 ApplicationReadyEvent 是“黄金时间点”当ApplicationReadyEvent发布时✅ 所有自动配置已经执行完✅ 你 setCallback 不会再被覆盖✅ RabbitTemplate 已处于最终状态✅ 应用已 ready行为可预测换句话说这是“房子装修完后再挂窗帘”的时刻。七、用生活比喻❌ 太早做构造方法 / PostConstruct你在装修阶段装窗帘后面装修队拆墙、刷漆、换窗户窗帘可能被拆掉、挂歪、甚至换成默认窗帘✅ ReadyEvent 做装修完家具都摆好了钥匙交付你再挂窗帘这就是最终状态不会再变八、几种常见初始化方式对比方式触发时机是否可能被自动配置覆盖推荐程度构造方法Bean 创建✅ 非常可能❌PostConstructBean 初始化✅ 可能⚠️InitializingBeanBean 初始化✅ 可能⚠️CommandLineRunner容器启动后很少✅✅ ApplicationReadyEvent应用完全就绪几乎不会✅✅✅九、更推荐的工程写法两种方案 A现在这种监听 ReadyEvent优点最直观时机最稳不影响自动配置方案 B用RabbitTemplateConfigurer/ Bean 后置增强高级如果你想更“Spring 风格”也可以考虑自定义RabbitTemplatebean慎重或用SmartInitializingSingleton或用EventListener(ApplicationReadyEvent.class)例如更简洁的写法ComponentSlf4jpublicclassRabbitTemplateCallbackConfig{privatefinalRabbitTemplaterabbitTemplate;publicRabbitTemplateCallbackConfig(RabbitTemplaterabbitTemplate){this.rabbitTemplaterabbitTemplate;}EventListener(ApplicationReadyEvent.class)publicvoidinit(){rabbitTemplate.setConfirmCallback((correlationData,ack,reason)-{...});rabbitTemplate.setReturnsCallback(returned-{...});}}这个和你现在做的事本质一样同样是“等 ready 再设置”。十、总结RabbitTemplate 的回调属于全局行为配置必须在自动配置结束后绑定。所以用ApplicationReadyEvent是最稳妥、最不踩坑的方式。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2421051.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!