当前位置: 首页 > news >正文

ApplicationListener 实战示例

ApplicationListener 是 Spring 事件驱动模型的核心接口,通过它可以监听容器发布的各种事件,实现组件间的松耦合通信。以下是它的常见用法:

1. 监听 Spring 内置生命周期事件和springboot容器启动周期事件

Spring 容器在启动、刷新、停止、关闭等阶段会发布相应事件,通过监听这些事件可以在特定时机执行初始化或清理工作。

ContextRefreshedEvent‌:容器初始化或刷新完成时触发,此时所有单例 Bean 已就绪。常用于加载缓存、启动定时任务等。
ContextStartedEvent‌:调用容器的 start() 方法时触发,可用于重启已停止的模块。
ContextStoppedEvent‌:调用容器的 stop() 方法时触发,适合暂停正在进行的任务。
ContextClosedEvent‌:容器关闭时触发,适合释放资源、关闭连接等清理操作。
ApplicationReadyEvent:spring boot 容器特有,应用完全启动就绪时触发。

示例:实现 ApplicationListener 并重写 onApplicationEvent,即可在容器刷新完成后执行自定义逻辑。

2. 自定义业务事件,实现业务解耦

当某个业务操作完成后需要触发一系列后续处理(如发短信、记日志、更新缓存),可以通过自定义事件将核心逻辑与附加逻辑分离。

定义事件‌:继承 ApplicationEvent,添加业务数据字段。
创建监听器‌:实现 ApplicationListener<自定义事件>,在 onApplicationEvent 中编写处理逻辑。
发布事件‌:通过注入 ApplicationEventPublisher 或直接使用 ApplicationContext.publishEvent() 发布事件。

这样,订单创建、用户注册等场景只需发布一个事件,对应的监听器就会自动执行后续操作,无需在核心代码中耦合这些逻辑。

3. 使用@EventListener注解简化监听

从 Spring 4.2 开始,可以在任意 Bean 的公开方法上使用@EventListener注解来声明事件监听器,无需实现 ApplicationListener 接口。

方法参数指定监听的事件类型,支持多个事件类型。
可以配合@Async实现异步处理,配合@Order控制执行顺序。
还可以通过@TransactionalEventListener绑定事务阶段(如事务提交后执行)。

这种方式代码更简洁,是目前推荐的做法。

4. 异步事件处理

默认情况下,事件监听器在发布事件的线程中同步执行。如果事件处理耗时较长,可以开启异步支持,避免阻塞主流程。

在监听方法上添加@Async注解,并启用 Spring 的异步执行能力(如 @EnableAsync)。
异步监听器将在独立的线程池中执行,提升系统的响应速度。

5. 控制监听器的执行顺序

当多个监听器监听同一事件时,可以通过@Order注解或实现 Ordered 接口来指定执行顺序。数值越小,优先级越高,越先执行。

6. 事务绑定事件监听

在数据库操作场景中,有时需要确保事件仅在事务成功提交后才触发(例如发送消息通知)。可以使用@TransactionalEventListener注解,并指定事务阶段(默认为 AFTER_COMMIT),这样监听器会在事务提交后执行,避免因事务回滚而产生不一致。

7. 在 Spring Boot 中通过 spring.factories 自动注册

在 Spring Boot 应用中,可以将自定义监听器的全限定类名配置在META-INF/spring.factories文件中:

org.springframework.context.ApplicationListener=com.example.MyListener

这样监听器会被自动加载,无需额外添加 @Component 等注解。

8. 监听 Web 特定事件

在 Web 应用中,还可以监听 RequestHandledEvent(或更具体的 ServletRequestHandledEvent),该事件在每次 HTTP 请求处理完成后发布,可用于记录请求日志、统计性能等。

这些用法覆盖了从容器生命周期管理到业务解耦、异步处理、事务绑定等常见场景,合理运用能显著提升系统的可扩展性和可维护性。

以下是ApplicationListener 的实战示例,从容器生命周期监听到业务解耦,覆盖最常见的应用场景。

一、监听容器刷新完成,执行初始化逻辑

这是最常用的内置事件监听场景。当 Spring 容器中所有单例 Bean 都初始化完毕后,ContextRefreshedEvent 会被发布,非常适合做缓存预热、数据预加载等操作。

importorg.springframework.context.ApplicationListener;importorg.springframework.context.event.ContextRefreshedEvent;importorg.springframework.stereotype.Component;@ComponentpublicclassContextRefreshListenerimplementsApplicationListener<ContextRefreshedEvent>{@OverridepublicvoidonApplicationEvent(ContextRefreshedEventevent){System.out.println("容器刷新完成,开始初始化操作");System.out.println("已加载的Bean数量: "+event.getApplicationContext().getBeanDefinitionCount());// 执行初始化逻辑initCache();preloadData();}privatevoidinitCache(){// 将热点数据加载到 Redis 或本地缓存System.out.println("缓存预热完成");}privatevoidpreloadData(){// 预加载字典表、配置项等System.out.println("数据预加载完成");}}

注意‌:如果应用中存在父子容器(比如 Spring MVC 的 DispatcherServlet 会创建子容器),ContextRefreshedEvent 可能会触发两次。可以通过判断 event.getApplicationContext() 是否为根容器来避免重复执行。

二、自定义业务事件,实现订单创建后的解耦处理

这是一个非常经典的业务解耦案例。订单创建成功后,需要发短信、发邮件、记日志等,如果全部写在 createOrder 方法里,代码会越来越臃肿。用事件机制就能把核心逻辑和附加逻辑彻底分开。
核心概念:
1.事件:extends ApplicationEvent 的类或者普通的对象(Spring 4.2+支持)
2.发布者:使用ApplicationEventPublisher 或者 ApplicationContext 来发布事件。
3.监听者:implements ApplicationListener<事件> 或者 使用@EventListener。

1. 定义事件
importorg.springframework.context.ApplicationEvent;publicclassOrderCreatedEventextendsApplicationEvent{privatefinalLongorderId;privatefinalStringcustomerEmail;privatefinalStringphoneNumber;publicOrderCreatedEvent(Objectsource,LongorderId,StringcustomerEmail,StringphoneNumber){super(source);this.orderId=orderId;this.customerEmail=customerEmail;this.phoneNumber=phoneNumber;}publicLonggetOrderId(){returnorderId;}publicStringgetCustomerEmail(){returncustomerEmail;}publicStringgetPhoneNumber(){returnphoneNumber;}}
2. 创建多个监听器(各司其职)
importorg.springframework.context.ApplicationListener;importorg.springframework.stereotype.Component;// 监听器1:发送短信@ComponentpublicclassSmsNotificationListenerimplementsApplicationListener<OrderCreatedEvent>{@OverridepublicvoidonApplicationEvent(OrderCreatedEventevent){System.out.println("发送短信到 "+event.getPhoneNumber()+":订单 "+event.getOrderId()+" 已创建成功!");// 调用短信服务接口...}}// 监听器2:发送邮件@ComponentpublicclassEmailNotificationListenerimplementsApplicationListener<OrderCreatedEvent>{@OverridepublicvoidonApplicationEvent(OrderCreatedEventevent){System.out.println("发送确认邮件到 "+event.getCustomerEmail()+":订单 "+event.getOrderId()+" 详情...");// 调用邮件服务接口...}}// 监听器3:记录审计日志@ComponentpublicclassAuditLogListenerimplementsApplicationListener<OrderCreatedEvent>{@OverridepublicvoidonApplicationEvent(OrderCreatedEventevent){System.out.println("记录审计日志:订单 "+event.getOrderId()+" 已创建");// 写入审计日志表...}}
3. 在业务代码中发布事件
importorg.springframework.context.ApplicationEventPublisher;importorg.springframework.stereotype.Service;@Service@RequiredArgsConstructorpublicclassOrderService{privatefinalApplicationEventPublishereventPublisher;publicvoidcreateOrder(){// 1. 核心业务:生成订单并保存到数据库LongorderId=12345L;System.out.println("订单 "+orderId+" 已生成并保存到数据库");// 2. 发布事件,后续的短信、邮件、日志由监听器异步/同步处理OrderCreatedEventevent=newOrderCreatedEvent(this,orderId,"user@example.com","13800138000");eventPublisher.publishEvent(event);//也可以注入ApplicationContext ,不推荐,相当于大炮打蚊子//private final ApplicationContext applicationContext ,//applicationContext.publishEvent(event);System.out.println("订单创建主流程结束");}}

这样一来,后续如果还要加「发放优惠券」「推送消息到 App」等逻辑,只需新增一个监听器即可,完全不用改动 OrderService 的核心代码。

三、使用 @EventListener 注解(更简洁的写法)

从 Spring 4.2 开始,不必实现 ApplicationListener 接口,直接用注解就能声明监听器,代码更简洁。

importorg.springframework.context.event.EventListener;importorg.springframework.stereotype.Component;@ComponentpublicclassOrderEventHandler{@EventListenerpublicvoidhandleOrderCreated(OrderCreatedEventevent){System.out.println("[注解方式] 收到订单创建事件,订单ID: "+event.getOrderId());// 处理逻辑...}}

还可以配合 @Async 实现异步处理,配合 @Order 控制执行顺序:

importorg.springframework.context.event.EventListener;importorg.springframework.core.annotation.Order;importorg.springframework.scheduling.annotation.Async;importorg.springframework.stereotype.Component;@ComponentpublicclassAsyncOrderEventHandler{@Async@EventListener@Order(1)publicvoidhandleOrderCreated(OrderCreatedEventevent){System.out.println("[异步处理] 订单 "+event.getOrderId()+" 的后置处理,不阻塞主线程");}}

四、事务绑定事件监听

有时需要确保事件‌只在数据库事务成功提交后才触发‌(比如发消息通知),否则事务回滚了消息却发出去了,就会造成数据不一致。这时用 @TransactionalEventListener:

importorg.springframework.stereotype.Component;importorg.springframework.transaction.event.TransactionPhase;importorg.springframework.transaction.event.TransactionalEventListener;@ComponentpublicclassTransactionalOrderHandler{@TransactionalEventListener(phase=TransactionPhase.AFTER_COMMIT)publicvoidhandleOrderCreatedAfterCommit(OrderCreatedEventevent){System.out.println("事务已提交,安全发送MQ消息,订单ID: "+event.getOrderId());// 发送消息到消息队列...}@TransactionalEventListener(phase=TransactionPhase.AFTER_ROLLBACK)publicvoidhandleOrderCreatedAfterRollback(OrderCreatedEventevent){System.out.println("事务已回滚,记录异常,订单ID: "+event.getOrderId());// 补偿或告警逻辑...}}

五、总结对比

场景推荐方式关键点
容器启动后初始化实现 ApplicationListener注意父子容器重复触发问题
业务解耦(同步)@EventListener 或实现接口代码简洁,推荐注解方式
业务解耦(异步)@Async + @EventListener需启用 @EnableAsync
事务提交后处理@TransactionalEventListener避免事务回滚导致数据不一致
控制执行顺序@Order 注解数值越小越先执行
http://www.gsyq.cn/news/1428221.html

相关文章:

  • QMCDecode:重构你的QQ音乐数字资产自由
  • TRALY深海鲨鱼鱼油三代vs一代:成分差异与养护实效对比 - 互联网科技品牌测评
  • 北京黄金回收去哪卖靠谱?2026年5月三大平台实测+避坑指南,这家真的零套路 - 资讯纵览
  • CS336 Assignment 1 BPE分词器训练初版(朴素版基础上优化)及后续优化方向分析
  • 2026报考指南:四川省内比较好的大学推荐 - 品牌2025
  • SteamAutoCrack项目深度解析:如何从零构建自动化游戏破解工具
  • 揭秘26年山东一卡通回收流程中的小技巧,轻松搞定! - 团团收购物卡回收
  • 银泰百货卡回收常见问题解答!2026新手最全答疑攻略 - 可可收公众号
  • 如何判断闲置银泰百货卡的回收价格是否合理? - 团团收购物卡回收
  • 三步解决B站视频下载难题:哔哩下载姬完全使用指南
  • 2026报考指南:四川文化艺术学院校园环境与设施介绍 - 品牌2025
  • 多尺度地理加权回归(MGWR):3步掌握空间异质性分析的终极指南
  • 2026义乌公司注册代办执照集群地址托管十大实力星榜:本土服务商深度测评 - 企业品牌优选推荐官
  • AI智能体人才招引实操指南:破局人才缺口,构建区域AI产业优势
  • 基于ESP32C3与A9G的便携式GPS追踪器全栈开发实战
  • 义乌市拓成企业管理咨询有限公司调研白皮书:义乌公司注册与全生命周期企业服务的专业伙伴 - 企业品牌优选推荐官
  • 有人说: 安装了个桌面版的OpenCode 。 和网页版有什么区别,?网页版大部分是一个平台,有的也有多个平台集成的。 通用AI客户端只装一个可以添加N个平台的API KEY
  • 2026年Q2中国泰山石优质厂家首选推荐:合肥飞宇石业有限公司电话18895462999 - 安互工业信息
  • 基于Teensy 4.1的模型火箭飞行计算机:从传感器融合到双伞回收控制
  • 保姆级教程:在Mac上彻底卸载ABC输入法并精细调校搜狗(含SIP关闭指南)
  • 3分钟掌握:网盘下载加速神器终极指南
  • 家里有百联卡长期闲置?分享一种更高效的资源回收思路 - 圆圆收
  • 【腾讯小龙虾 WorkBuddy 专栏 03】技能(Skills)制作全教程!自定义技能编写、导出分享、导入使用一步到位
  • 终极MapleStory游戏资源编辑指南:如何使用Harepacker-resurrected一站式工具
  • 不止于编译:深入TI CCS的Post-build,解锁自动化构建与生产部署
  • 【架构设计】大型分布式系统架构设计实战
  • Java反射机制
  • 【AI驱动A/B测试革命】:20年实战验证的5大整合陷阱与避坑指南
  • 5个技巧掌握AI图像控制:开源预处理工具终极指南
  • DeepSeek-Coder-V2实战解析:企业级代码智能的架构选择与部署策略