Java Spring ApplicationEvent 概述

一、Spring 事件机制核心概念

1. 事件驱动架构模型

  • 发布-订阅模式:解耦事件生产者和消费者
  • 观察者模式:监听器监听特定事件
  • 事件驱动优势
    • 组件间松耦合
    • 系统扩展性好
    • 支持异步处理
    • 事件溯源支持

2. 核心组件

组件作用实现方式
ApplicationEvent事件基类自定义事件需继承
ApplicationEventPublisher事件发布接口通过Spring容器注入
ApplicationListener事件监听接口实现接口或使用@EventListener

二、代码示例解析

1. 事件定义 (KnowledgeService.java)

@Getter
public static final class ImportedKnowledgeEvent extends ApplicationEvent {private final Knowledge knowledge;private final KWDocument document;// 构造器1:只有knowledgepublic ImportedKnowledgeEvent(Object source, Knowledge knowledge) {super(source);this.knowledge = knowledge;this.document = null;}// 构造器2:knowledge + documentpublic ImportedKnowledgeEvent(Object source, Knowledge knowledge, KWDocument document) {super(source);this.knowledge = knowledge;this.document = document;}
}

关键点

  • 继承ApplicationEvent基类
  • 使用final字段保证事件不可变性
  • 提供多种构造器支持不同场景
  • 使用@Getter(Lombok)提供访问方法

2. 事件发布 (KnowledgeService.java)

@Service
public class KnowledgeService {@Autowiredprotected ApplicationEventPublisher eventPublisher;public void imports() {// 发布简单知识导入事件eventPublisher.publishEvent(new ImportedKnowledgeEvent(this, new Knowledge()));// 发布知识+文档导入事件eventPublisher.publishEvent(new ImportedKnowledgeEvent(this, new Knowledge(), new KWDocument()));}
}

发布模式

  1. 注入ApplicationEventPublisher
  2. 创建事件对象(包含业务数据)
  3. 调用publishEvent()发布
  4. 支持多种事件类型重载

3. 事件监听 (KnowledgeRagflowService.java)

@Service
public class KnowledgeRagflowService extends KnowledgeService {@EventListenerpublic void importedKnowledge(KnowledgeService.ImportedKnowledgeEvent event) {if (event.getDocument() != null) {dealDocument(event.getKnowledge(), event.getDocument());} else {dealKnowledge(event.getKnowledge());}}private void dealDocument(Knowledge knowledge, Document document) {// 处理文档逻辑}private void dealKnowledge(Knowledge knowledge) {// 处理知识逻辑}
}

监听器特点

  • 使用@EventListener注解简化实现
  • 方法参数决定监听的事件类型
  • 支持事件内容判断(区分有无document)
  • 私有方法封装具体处理逻辑

三、高级应用技巧

1. 条件监听

@EventListener(condition = "#event.document != null")
public void handleDocumentEvent(ImportedKnowledgeEvent event) {// 仅处理包含document的事件
}

2. 异步事件处理

@Async
@EventListener
public void asyncHandleEvent(ImportedKnowledgeEvent event) {// 异步处理耗时操作
}

配置要求

  1. 主类添加@EnableAsync
  2. 配置线程池:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.initialize();return executor;}
}

3. 监听器执行顺序

@Order(1)
@EventListener
public void firstListener(ImportedKnowledgeEvent event) {// 最先执行
}@Order(2)
@EventListener
public void secondListener(ImportedKnowledgeEvent event) {// 其次执行
}

4. 事务绑定事件

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void afterCommitEvent(ImportedKnowledgeEvent event) {// 事务提交后执行
}

事务阶段选项

  • AFTER_COMMIT(默认):事务成功提交后
  • AFTER_ROLLBACK:事务回滚后
  • AFTER_COMPLETION:事务完成后(提交或回滚)
  • BEFORE_COMMIT:事务提交前

四、最佳实践

1. 事件设计原则

  • 单一职责:一个事件只携带一种业务变更
  • 不可变性:事件发布后内容不可修改
  • 上下文完整:包含所有必要业务数据
  • 命名规范:使用过去时态(如ImportedKnowledgeEvent

2. 性能优化

  • 同步/异步选择
    事件发布
    是否耗时?
    异步处理
    同步处理
  • 批量处理:对高频事件进行批量合并
  • 事件过滤:在监听器内部添加条件判断

3. 错误处理

@EventListener
public void handleEvent(ImportedKnowledgeEvent event) {try {// 业务处理} catch (Exception e) {// 1. 记录错误日志// 2. 发布错误处理事件// 3. 重试机制(如Spring Retry)}
}

4. 测试策略

@SpringBootTest
class KnowledgeEventTest {@Autowiredprivate ApplicationEventPublisher eventPublisher;@MockBeanprivate KnowledgeRagflowService ragflowService;@Testvoid shouldTriggerListenerWhenPublishEvent() {// 准备测试事件ImportedKnowledgeEvent event = new ImportedKnowledgeEvent(this, new Knowledge());// 发布事件eventPublisher.publishEvent(event);// 验证监听器调用verify(ragflowService, timeout(1000)).importedKnowledge(event);}
}

五、典型应用场景

  1. 业务状态变更通知

    • 知识导入完成通知
    • 文档处理状态更新
  2. 跨模块协作

    • 知识导入后触发索引更新
    • 文档处理完成后通知搜索服务
  3. 系统生命周期事件

    @EventListener
    public void onApplicationReady(ContextRefreshedEvent event) {// 应用启动完成后初始化资源
    }
    
  4. 审计日志记录

    @EventListener
    public void auditLog(ImportedKnowledgeEvent event) {log.info("Knowledge imported: {}", event.getKnowledge().getId());
    }
    
  5. 业务流程编排

    ImportService EventBus IndexService NotificationService 发布ImportedKnowledgeEvent 触发索引更新 触发通知发送 ImportService EventBus IndexService NotificationService

六、常见问题解决方案

  1. 监听器未触发

    • 检查事件类型是否匹配
    • 确认监听器在Spring容器中
    • 验证事件是否成功发布
  2. 循环事件触发

    // 使用标记防止循环
    public void imports() {if (!EventContext.isEventProcessing()) {eventPublisher.publishEvent(...);}
    }
    
  3. 事件数据过大

    • 改为传递引用ID而非整个对象
    • 使用DTO精简数据
    • 添加@Lazy注解延迟加载
  4. 监听器执行顺序问题

    • 使用@Order明确顺序
    • 拆分事件避免依赖

总结

Spring ApplicationEvent 提供了强大的事件驱动编程模型,通过示例中的KnowledgeServiceKnowledgeRagflowService展示了:

  • 如何定义包含业务数据的事件
  • 多种事件发布方式
  • 使用@EventListener简化监听器实现
  • 根据事件内容执行不同处理逻辑

在实际应用中,应结合:

  1. 异步处理提升性能
  2. 事务绑定确保数据一致性
  3. 条件过滤优化事件处理
  4. 完善错误处理机制

遵循"高内聚、低耦合"原则,合理使用事件驱动架构,可以显著提升系统的扩展性和可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/86954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring核心框架完全指南 - 基础知识全解析

📖 目录 🌟 Spring框架简介 🏗️ IoC容器详解 💉 依赖注入(DI)深入理解 ⚙️ Bean配置与管理 🎯 Bean的作用域 🔄 Bean生命周期 🎭 面向切面编程(AOP) 📝 Spring注解详解 📁 资源管理 📢 事件机制 🔤 SpEL表达式语言 🎯 实战案例 📚 总…

Parasoft C++Test软件集成测试(部件测试)_操作指南

系列文章目录 Parasoft C++Test软件静态分析:操作指南(编码规范、质量度量)、常见问题及处理 Parasoft C++Test软件单元测试:操作指南、实例讲解、常见问题及处理 Parasoft C++Test软件集成测试:操作指南、实例讲解、常见问题及处理 进阶扩展:自动生成静态分析文档、自动…

聊一聊 Linux 上对函数进行 hook 的两种方式

一:背景 1. 讲故事 前两篇我们介绍了 Minhook 在 Windows 平台上的强大功效,这一篇我们来聊一聊如何在 Linux 上对函数进行hook,这里介绍两种方式。 轻量级的 LD_PRELOAD 拦截 LD_PRELOAD是一种共享库拦截,这种方式的优点在于…

【免费分享】GWO-BP-AdaBoost预测!灰狼优化、人工神经网络与AdaBoost集成学习算法预测研究

一、模型组成原理 1. 灰狼优化算法(GWO) 核心思想:模拟灰狼群体的社会等级和狩猎行为(包围、跟踪、攻击猎物),通过α、β、δ三级领导层引导种群搜索最优解。算法流程包括: 社会分层&#xff…

matlab实现非线性Granger因果检验

matlab程序包。用于格兰杰因果分析,分析数据时,直接带入数据即可。 hjt2/README , 1804 hjt2/c-code/Makefile , 57 hjt2/c-code/hjt2_tval.c , 10862 hjt2/matlab/spx_rp.dat , 175202 hjt2/matlab/spx_ur.dat , 174522 hjt2/matlab/spx_uv.dat , 1745…

从SQL Server到分布式大数据平台:重构企业数据架构

在企业数字化加速的背景下,越来越多的组织开始意识到:传统的数据系统正逐渐成为增长的“瓶颈”而非“助力”。其中,SQL Server 作为许多企业IT架构中曾经的中坚力量,正面临前所未有的挑战。它曾以稳定、易用、成本可控等优势&…

【网关】互联网公司的接入网关和业务网关怎么设计

网关 网关基础知识 RGW全称 Red GateWay :小红书网关(网关英文:Gateway; 接入网关:Access Gateway) 网关(通用):Gateway 接入网关:API Gateway、Access Gateway 业务网关…

安全虚拟磁盘技术的创新与实践

文章目录 前言一、数据安全保护的新挑战1. 数据安全态势日益严峻,法律法规陆续出台2. 加强数据安全管控成为银行数据安全管理核心之一3. 银行终端数据安全管控存在的难题 二、安全虚拟磁盘的探索与实践1. 敏感文件的入盘及操作2. 敏感文件的流转及出盘三、安全虚拟磁…

uni-app项目实战笔记4--使用组件具名插槽slot定义公共标题模块

先来看效果: 如图,“每日推荐”,“专题精选”这些公共标题有相同的地方,也有自己的独特的地方,像这类有共性又有个性的可考虑使用slot插槽来实现。 实现步骤: 1.在前面文章创建的公共组件common-title定义…

Appium + Java 测试全流程

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】

vue3 双容器自动扩展布局 根据 内容的多少 动态定义宽度

需求: 左右两个列表 挨着排列,当左边内容超出滚动条时,换列显示,右边的列表随之移动 效果图: 1.左边数据:10,右边数据:5 2.左边数据:30,右边数据&#xff…

linux-java部署

version: 3 services:nacos_host:image: nacos/nacos-server:v2.2.0restart: alwayscontainer_name: nacos_hostenvironment:- MODEstandalone- PREFER_HOST_MODEhostnamevolumes:- ./sores/nacos/log:/home/nacos/logsports:- 8848:8848- 9848:9848 #2.0新增了两个端口&#x…

010502管道符_防火墙出入站_不回显带外-渗透命令-基础入门-网络安全

文章目录 1 管道符2 防火墙出入站3 不回显外带典型场景常见OOB通道实现示例(以DNS为例)1. 利用DNS外带数据2. 使用工具监听 防御建议扩展:无回显OOB自动化工具注意事项演示结语 1 管道符 | (管道符号) ||(…

智慧养老与数字健康:科技赋能老年生活,构建全方位养老体系

在全球人口老龄化进程不断加速的当下,我国的老龄化程度也日益加深。 截至 2023 年末,我国 60 岁及以上人口达 2.97 亿人,占总人口的 21.1%,其中 65 岁及以上人口为 2.17 亿人,占总人口的 15.4%。 养老问题已成为全社…

在 cuda 基础环境中安装完整的cupy

nvidia/cuda:12.6.3-cudnn-devel-ubuntu22.04 1. 创建 cuda 基础容器 export NUM2 && \ sudo docker run --gpus all -it \ --name cupy_LHL_${NUM} \ -v /home/jimmy/ex_cupy/tmp${NUM}:/root/tmp${NUM} \ -v /home/jimmy/.ssh:/root/.ssh \ nvidia/cuda:12.6.3-dev…

OB Cloud × 海牙湾:打造高效灵活的金融科技 AI 数字化解决方案

在金融行业国产升级的战略背景下,上海海牙湾信息科技有限公司凭借其服务银行客户的深厚积累,近日完成重大技术升级 —— 将金融行业积分生态的SaaS平台、数字化营销中台及企业供应链管理系统全部迁移至完全自主研发的 OB Cloud 一体化云数据库。依托OB C…

LarkXR 赋能AI x XR数字供应链:引领智能设计、数字孪生与零售新未来

全球零售业数字化转型 在数字化浪潮的推动下,零售业正经历一场从设计到生产再到终端消费的全链路变革。消费者对个性化、沉浸式体验的需求日益增长,而企业也亟需通过数字化手段提升效率、降低成本并增强竞争力。Paraverse平行云的LarkXR实时云渲染技术&…

go语言快速入门

代码仓库 gitee 如何运行 以打印hello world为例 // main.go package main // package为main的文件可以直接运行import "fmt"func main() {fmt.Println("Hello, World!") }# 直接运行 go run main.go # 或者编译后运行 go build main.go ./main.exe变量…

使用麒麟V10操作系统的KVM服务,但麒麟V10存在高危漏洞无法修复?

麒麟V10操作系统之KVM部署虚拟机_麒麟v10安装kvm-CSDN博客文章浏览阅读3.7k次,点赞30次,收藏25次。本文介绍了在麒麟V10操作系统上部署KVM虚拟机的详细步骤,包括检查虚拟化支持、安装KVM组件、创建虚拟机、配置网络桥接,以及解决可…

PG、SprinBoot项目报错,表不存在

1、用户名密码错误 2、数据库IP和数据库名称错误 3、类似于如下的表结构 PG 默认扫描PUBLIC下面的表,需要手动指定schema,currentSchemaswdn_new url: jdbc:postgresql://${PGSQL_HOST:127.0.0.1}:${PGSQL_PORT:5432}/swdn_new?currentSchemaswdn_ne…