Java Spring ApplicationEvent 代碼示例解析
一、Spring 事件機(jī)制核心概念
1. 事件驅(qū)動(dòng)架構(gòu)模型
- 發(fā)布-訂閱模式:解耦事件生產(chǎn)者和消費(fèi)者
- 觀察者模式:監(jiān)聽器監(jiān)聽特定事件
- 事件驅(qū)動(dòng)優(yōu)勢(shì):
- 組件間松耦合
- 系統(tǒng)擴(kuò)展性好
- 支持異步處理
- 事件溯源支持
2. 核心組件
組件 | 作用 | 實(shí)現(xiàn)方式 |
---|---|---|
ApplicationEvent | 事件基類 | 自定義事件需繼承 |
ApplicationEventPublisher | 事件發(fā)布接口 | 通過(guò)Spring容器注入 |
ApplicationListener | 事件監(jiān)聽接口 | 實(shí)現(xiàn)接口或使用@EventListener |
二、代碼示例解析
1. 事件定義 (KnowledgeService.java)
@Getter public static final class ImportedKnowledgeEvent extends ApplicationEvent { private final Knowledge knowledge; private final KWDocument document; // 構(gòu)造器1:只有knowledge public ImportedKnowledgeEvent(Object source, Knowledge knowledge) { super(source); this.knowledge = knowledge; this.document = null; } // 構(gòu)造器2:knowledge + document public ImportedKnowledgeEvent(Object source, Knowledge knowledge, KWDocument document) { super(source); this.knowledge = knowledge; this.document = document; } }
關(guān)鍵點(diǎn):
- 繼承
ApplicationEvent
基類 - 使用final字段保證事件不可變性
- 提供多種構(gòu)造器支持不同場(chǎng)景
- 使用
@Getter
(Lombok)提供訪問(wèn)方法
2. 事件發(fā)布 (KnowledgeService.java)
@Service public class KnowledgeService { @Autowired protected ApplicationEventPublisher eventPublisher; public void imports() { // 發(fā)布簡(jiǎn)單知識(shí)導(dǎo)入事件 eventPublisher.publishEvent(new ImportedKnowledgeEvent(this, new Knowledge())); // 發(fā)布知識(shí)+文檔導(dǎo)入事件 eventPublisher.publishEvent(new ImportedKnowledgeEvent(this, new Knowledge(), new KWDocument())); } }
發(fā)布模式:
- 注入
ApplicationEventPublisher
- 創(chuàng)建事件對(duì)象(包含業(yè)務(wù)數(shù)據(jù))
- 調(diào)用
publishEvent()
發(fā)布 - 支持多種事件類型重載
3. 事件監(jiān)聽 (KnowledgeRagflowService.java)
@Service public class KnowledgeRagflowService extends KnowledgeService { @EventListener public 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) { // 處理知識(shí)邏輯 } }
監(jiān)聽器特點(diǎn):
- 使用
@EventListener
注解簡(jiǎn)化實(shí)現(xiàn) - 方法參數(shù)決定監(jiān)聽的事件類型
- 支持事件內(nèi)容判斷(區(qū)分有無(wú)document)
- 私有方法封裝具體處理邏輯
三、高級(jí)應(yīng)用技巧
1. 條件監(jiān)聽
@EventListener(condition = "#event.document != null") public void handleDocumentEvent(ImportedKnowledgeEvent event) { // 僅處理包含document的事件 }
2. 異步事件處理
@Async @EventListener public void asyncHandleEvent(ImportedKnowledgeEvent event) { // 異步處理耗時(shí)操作 }
配置要求:
- 主類添加
@EnableAsync
- 配置線程池:
@Configuration @EnableAsync public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.initialize(); return executor; } }
3. 監(jiān)聽器執(zhí)行順序
@Order(1) @EventListener public void firstListener(ImportedKnowledgeEvent event) { // 最先執(zhí)行 } @Order(2) @EventListener public void secondListener(ImportedKnowledgeEvent event) { // 其次執(zhí)行 }
4. 事務(wù)綁定事件
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) public void afterCommitEvent(ImportedKnowledgeEvent event) { // 事務(wù)提交后執(zhí)行 }
事務(wù)階段選項(xiàng):
AFTER_COMMIT
(默認(rèn)):事務(wù)成功提交后AFTER_ROLLBACK
:事務(wù)回滾后AFTER_COMPLETION
:事務(wù)完成后(提交或回滾)BEFORE_COMMIT
:事務(wù)提交前
四、最佳實(shí)踐
1. 事件設(shè)計(jì)原則
- 單一職責(zé):一個(gè)事件只攜帶一種業(yè)務(wù)變更
- 不可變性:事件發(fā)布后內(nèi)容不可修改
- 上下文完整:包含所有必要業(yè)務(wù)數(shù)據(jù)
- 命名規(guī)范:使用過(guò)去時(shí)態(tài)(如
ImportedKnowledgeEvent
)
2. 性能優(yōu)化
- 同步/異步選擇:
- 批量處理:對(duì)高頻事件進(jìn)行批量合并
- 事件過(guò)濾:在監(jiān)聽器內(nèi)部添加條件判斷
3. 錯(cuò)誤處理
@EventListener public void handleEvent(ImportedKnowledgeEvent event) { try { // 業(yè)務(wù)處理 } catch (Exception e) { // 1. 記錄錯(cuò)誤日志 // 2. 發(fā)布錯(cuò)誤處理事件 // 3. 重試機(jī)制(如Spring Retry) } }
4. 測(cè)試策略
@SpringBootTest class KnowledgeEventTest { @Autowired private ApplicationEventPublisher eventPublisher; @MockBean private KnowledgeRagflowService ragflowService; @Test void shouldTriggerListenerWhenPublishEvent() { // 準(zhǔn)備測(cè)試事件 ImportedKnowledgeEvent event = new ImportedKnowledgeEvent(this, new Knowledge()); // 發(fā)布事件 eventPublisher.publishEvent(event); // 驗(yàn)證監(jiān)聽器調(diào)用 verify(ragflowService, timeout(1000)).importedKnowledge(event); } }
五、典型應(yīng)用場(chǎng)景
業(yè)務(wù)狀態(tài)變更通知
- 知識(shí)導(dǎo)入完成通知
- 文檔處理狀態(tài)更新
跨模塊協(xié)作
- 知識(shí)導(dǎo)入后觸發(fā)索引更新
- 文檔處理完成后通知搜索服務(wù)
系統(tǒng)生命周期事件
@EventListener public void onApplicationReady(ContextRefreshedEvent event) { // 應(yīng)用啟動(dòng)完成后初始化資源 }
審計(jì)日志記錄
@EventListener public void auditLog(ImportedKnowledgeEvent event) { log.info("Knowledge imported: {}", event.getKnowledge().getId()); }
業(yè)務(wù)流程編排
六、常見問(wèn)題解決方案
監(jiān)聽器未觸發(fā)
- 檢查事件類型是否匹配
- 確認(rèn)監(jiān)聽器在Spring容器中
- 驗(yàn)證事件是否成功發(fā)布
循環(huán)事件觸發(fā)
// 使用標(biāo)記防止循環(huán) public void imports() { if (!EventContext.isEventProcessing()) { eventPublisher.publishEvent(...); } }
事件數(shù)據(jù)過(guò)大
- 改為傳遞引用ID而非整個(gè)對(duì)象
- 使用DTO精簡(jiǎn)數(shù)據(jù)
- 添加
@Lazy
注解延遲加載
監(jiān)聽器執(zhí)行順序問(wèn)題
- 使用
@Order
明確順序 - 拆分事件避免依賴
- 使用
總結(jié)
Spring ApplicationEvent 提供了強(qiáng)大的事件驅(qū)動(dòng)編程模型,通過(guò)示例中的KnowledgeService
和KnowledgeRagflowService
展示了:
- 如何定義包含業(yè)務(wù)數(shù)據(jù)的事件
- 多種事件發(fā)布方式
- 使用
@EventListener
簡(jiǎn)化監(jiān)聽器實(shí)現(xiàn) - 根據(jù)事件內(nèi)容執(zhí)行不同處理邏輯
在實(shí)際應(yīng)用中,應(yīng)結(jié)合:
- 異步處理提升性能
- 事務(wù)綁定確保數(shù)據(jù)一致性
- 條件過(guò)濾優(yōu)化事件處理
- 完善錯(cuò)誤處理機(jī)制
遵循"高內(nèi)聚、低耦合"原則,合理使用事件驅(qū)動(dòng)架構(gòu),可以顯著提升系統(tǒng)的擴(kuò)展性和可維護(hù)性。
到此這篇關(guān)于Java Spring ApplicationEvent 代碼示例解析的文章就介紹到這了,更多相關(guān)Spring ApplicationEvent 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中ApplicationEvent的使用步驟詳解
- Spring中ApplicationEvent事件機(jī)制源碼詳解
- Spring中ApplicationEventPublisher發(fā)布訂閱模式的實(shí)現(xiàn)
- SpringBoot使用ApplicationEvent&Listener完成業(yè)務(wù)解耦
- 使用Spring的ApplicationEvent實(shí)現(xiàn)本地事件驅(qū)動(dòng)的實(shí)現(xiàn)方法
- SpringBoot中ApplicationEvent和ApplicationListener用法小結(jié)
- 基于Spring Boot應(yīng)用ApplicationEvent案例場(chǎng)景
- 詳解SpringBoot實(shí)現(xiàn)ApplicationEvent事件的監(jiān)聽與發(fā)布
- 詳解SpringBoot 發(fā)布ApplicationEventPublisher和監(jiān)聽ApplicationEvent事件
相關(guān)文章
java利用CompletionService保證任務(wù)先完成先獲取到執(zhí)行結(jié)果
這篇文章主要為大家詳細(xì)介紹了java如何利用CompletionService來(lái)保證任務(wù)先完成先獲取到執(zhí)行結(jié)果,文中的示例代碼講解詳細(xì),需要的可以參考下2023-08-08Java簡(jiǎn)單使用EasyExcel操作讀寫excel的步驟與要點(diǎn)
相信現(xiàn)在很多搞后端的同學(xué)大部分做的都是后臺(tái)管理系統(tǒng),那么管理系統(tǒng)就肯定免不了Excel的導(dǎo)出導(dǎo)入功能,下面這篇文章主要給大家介紹了關(guān)于Java簡(jiǎn)單使用EasyExcel操作讀寫excel的步驟與要點(diǎn),需要的朋友可以參考下2022-09-09Java系統(tǒng)環(huán)境變量配置全過(guò)程
本文介紹了如何配置Windows系統(tǒng)中的PATH和CLASSPATH環(huán)境變量,以及如何使用這些變量來(lái)運(yùn)行Java程序,步驟包括查看系統(tǒng)屬性、編輯環(huán)境變量、添加路徑、驗(yàn)證設(shè)置等,通過(guò)這些步驟,用戶可以永久性地保存PATH和CLASSPATH環(huán)境變量的設(shè)置,從而方便地運(yùn)行Java程序2024-11-11SpringBoot @PathVariable使用時(shí)遇到的問(wèn)題及解決
這篇文章主要介紹了SpringBoot @PathVariable使用時(shí)遇到的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10SpringBoot整合Lettuce redis過(guò)程解析
這篇文章主要介紹了SpringBoot整合Lettuce redis過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10MacBook Java開發(fā)環(huán)境搭建的詳細(xì)步驟(新手必備)
本文主要介紹了MacBook Java開發(fā)環(huán)境搭建,文中通過(guò)圖文示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Java實(shí)現(xiàn)http請(qǐng)求文件流對(duì)帶寬限速獲取md5值
文章介紹了如何在進(jìn)行HTTP請(qǐng)求下載大數(shù)據(jù)時(shí)處理帶寬限制和并發(fā)問(wèn)題,通過(guò)使用緩沖區(qū)和限速邏輯,可以有效控制下載速度,避免掉包和數(shù)據(jù)丟失,核心公式基于帶寬和已下載字節(jié)數(shù)計(jì)算預(yù)期耗時(shí),并通過(guò)Thread.sleep()進(jìn)行動(dòng)態(tài)休眠補(bǔ)償,感興趣的朋友一起看看吧2025-02-02java工具類之實(shí)現(xiàn)java獲取文件行數(shù)
這篇文章主要介紹了一個(gè)java工具類,可以取得當(dāng)前項(xiàng)目中所有java文件總行數(shù),代碼行數(shù),注釋行數(shù),空白行數(shù),需要的朋友可以參考下2014-03-03