电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解Spring事件發布與監聽機制

瀏覽:43日期:2023-07-05 14:44:49
目錄一、ApplicationContext 事件機制二、ApplicationListener 監聽器三、ApplicationEvent 事件四、自定義事件和監聽器五、注解式監聽器一、ApplicationContext 事件機制

ApplicationContext 事件機制采用觀察者設計模式來實現,通過 ApplicationEvent 事件類和 ApplicationListener 監聽器接口,可以實現 ApplicationContext 事件發布與處理。

每當 ApplicationContext 發布 ApplicationEvent 時,如果 Spring 容器中有 ApplicationListener bean,則監聽器會被觸發執行相應的處理。當然,ApplicationEvent 事件的發布需要顯示觸發,要么 Spring 顯示觸發,要么我們顯示觸發。

二、ApplicationListener 監聽器

定義應用監聽器需要實現的接口。此接口繼承了 JDK 標準的事件監聽器接口 EventListener,EventListener 接口是一個空的標記接口,推薦所有事件監聽器必須要繼承它。

package org.springframework.context;import java.util.EventListener;@FunctionalInterfacepublic interface ApplicationListener<E extends ApplicationEvent> extends EventListener {/** * 處理應用事件 */void onApplicationEvent(E event);}

package java.util;public interface EventListener {}

ApplicationListener 是個泛型接口,我們自定義此接口的實現類時,如果指定了泛型的具體事件類,那么只會監聽此事件。如果不指定具體的泛型,則會監聽 ApplicationEvent 抽象類的所有子類事件。

如下我們定義一個監聽器,監聽具體的事件,例如監聽 ApplicationStartedEvent 事件。

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.boot.context.event.ApplicationStartedEvent;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class MyApplicationListener implements ApplicationListener<ApplicationStartedEvent> { @Override public void onApplicationEvent(ApplicationStartedEvent event) {log.info('>>> MyApplicationListener:{}', event); }}

啟動服務,會發現在服務啟動后,此監聽器被觸發了。

詳解Spring事件發布與監聽機制

如果不指定具體的泛型類,則會監聽 ApplicationEvent 抽象類的所有子類事件。如下所示:

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.context.ApplicationEvent;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class MyApplicationListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationEvent event) {log.info('>>> MyApplicationListener:{}', event); }}

詳解Spring事件發布與監聽機制

注意,監聽器類的 bean 要注入到 Spring 容器中,不然不會生效。一種是使用注解注入,例如 @Component。另外可以使用 SpringApplicationBuilder.listeners() 方法添加,不過這兩種方式有區別的,看以下示例。

首先我們使用 @Component 注解方式,服務啟動時,監視到了2個事件:

ApplicationStartedEvent ApplicationReadyEvent

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.boot.context.event.SpringApplicationEvent;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class MyApplicationListener implements ApplicationListener<SpringApplicationEvent> { @Override public void onApplicationEvent(SpringApplicationEvent event) {log.info('>>> MyApplicationListener:{}', event); }}

詳解Spring事件發布與監聽機制

而使用 SpringApplicationBuilder.listeners() 方法添加監聽器,服務啟動時,監聽到了5個事件:

ApplicationEnvironmentPreparedEvent ApplicationContextInitializedEvent ApplicationPreparedEvent ApplicationStartedEvent ApplicationReadyEvent

package com.chenpi;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplicationpublic class Application { public static void main(String[] args) {// SpringApplication.run(Application.class, args);SpringApplication app = new SpringApplicationBuilder(Application.class).listeners(new MyApplicationListener()).build();app.run(args); }}

詳解Spring事件發布與監聽機制

其實這是和監聽器 bean 注冊的時機有關,@component 注解的監聽器 bean 只有在 bean 初始化注冊完后才能使用;而通過 SpringApplicationBuilder.listeners() 添加的監聽器 bean 是在容器啟動前,所以監聽到的事件比較多。但是注意,這兩個不要同時使用,不然監聽器會重復執行兩遍。

如果你想在監聽器 bean 中注入其他 bean(例如 @Autowired),那最好是使用注解形式,因為如果太早發布監聽器,可能其他 bean 還未初始化完成,可能會報錯。

三、ApplicationEvent 事件

ApplicationEvent 是所有應用事件需要繼承的抽象類。它繼承了 EventObject 類,EventObject 是所有事件的根類,這個類有個 Object 類型的對象 source,代表事件源。所有繼承它的類的構造函數都必須要顯示傳遞這個事件源。

package org.springframework.context;import java.util.EventObject;public abstract class ApplicationEvent extends EventObject {private static final long serialVersionUID = 7099057708183571937L;// 發布事件的系統時間private final long timestamp;public ApplicationEvent(Object source) {super(source);this.timestamp = System.currentTimeMillis();}public final long getTimestamp() {return this.timestamp;}}

package java.util;public class EventObject implements java.io.Serializable { private static final long serialVersionUID = 5516075349620653480L; protected transient Object source; public EventObject(Object source) {if (source == null) throw new IllegalArgumentException('null source');this.source = source; } public Object getSource() {return source; } public String toString() {return getClass().getName() + '[source=' + source + ']'; }}

在 Spring 中,比較重要的事件類是 SpringApplicationEvent。Spring 有一些內置的事件,當完成某種操作時會觸發某些事件。這些內置事件繼承 SpringApplicationEvent 抽象類。SpringApplicationEvent 繼承 ApplicationEvent 并增加了字符串數組參數字段 args。

@SuppressWarnings('serial')public abstract class SpringApplicationEvent extends ApplicationEvent {private final String[] args;public SpringApplicationEvent(SpringApplication application, String[] args) {super(application);this.args = args;}public SpringApplication getSpringApplication() {return (SpringApplication) getSource();}public final String[] getArgs() {return this.args;}}

詳解Spring事件發布與監聽機制

我們可以編寫自己的監聽器,然后監聽這些事件,實現自己的業務邏輯。例如編寫 ApplicationListener 接口的實現類,監聽 ContextStartedEvent 事件,當應用容器 ApplicationContext 啟動時,會發布該事件,所以我們編寫的監聽器會被觸發。

ContextRefreshedEvent:ApplicationContext 被初始化或刷新時,事件被發布。ConfigurableApplicationContext接口中的 refresh() 方法被調用也會觸發事件發布。初始化是指所有的 Bean 被成功裝載,后處理 Bean 被檢測并激活,所有單例 Bean 被預實例化,ApplicationContext 容器已就緒可用。 ContextStartedEvent:應用程序上下文被刷新后,但在任何 ApplicationRunner 和 CommandLineRunner 被調用之前,發布此事件。 ApplicationReadyEvent:此事件會盡可能晚地被發布,以表明應用程序已準備好為請求提供服務。事件源是SpringApplication 本身,但是要注意修改它的內部狀態,因為到那時所有初始化步驟都已經完成了。 ContextStoppedEvent:ConfigurableApplicationContext 接口的 stop() 被調用停止 ApplicationContext 時,事件被發布。 ContextClosedEvent:ConfigurableApplicationContext 接口的 close() 被調用關閉 ApplicationContext 時,事件被發布。注意,一個已關閉的上下文到達生命周期末端后,它不能被刷新或重啟。 ApplicationFailedEvent:當應用啟動失敗后發布事件。 ApplicationEnvironmentPreparedEvent:事件是在 SpringApplication 啟動時發布的,并且首次檢查和修改 Environment 時,此時上 ApplicationContext 還沒有創建。 ApplicationPreparedEvent:事件發布時,SpringApplication 正在啟動,ApplicationContext 已經完全準備好,但沒有刷新。在這個階段,將加載 bean definitions 并準備使用 Environment。 RequestHandledEvent:這是一個 web 事件,只能應用于使用 DispatcherServlet 的 Web 應用。在使用 Spring 作為前端的 MVC 控制器時,當 Spring 處理用戶請求結束后,系統會自動觸發該事件。四、自定義事件和監聽器

前面介紹了自定義監聽器,然后監聽 Spring 原有的事件。下面介紹自定義事件和自定義監聽器,然后在程序中發布事件,觸發監聽器執行,實現自己的業務邏輯。

首先自定義事件,繼承 ApplicationEvent,當然事件可以自定義自己的屬性。

package com.chenpi;import lombok.Getter;import lombok.Setter;import lombok.ToString;import org.springframework.context.ApplicationEvent;@Getter@Setterpublic class MyApplicationEvent extends ApplicationEvent { // 事件可以增加自己的屬性 private String myField; public MyApplicationEvent(Object source, String myField) {// 綁定事件源super(source);this.myField = myField; } @Override public String toString() {return 'MyApplicationEvent{' + 'myField=’' + myField + ’’’ + ', source=' + source + ’}’; }}

然后自定義監聽器,監聽我們自定義的事件。

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.context.ApplicationListener;@Slf4jpublic class MyApplicationListener implements ApplicationListener<MyApplicationEvent> { @Override public void onApplicationEvent(MyApplicationEvent event) {log.info('>>> MyApplicationListener:{}', event); }}

注冊監聽器和發布事件。注冊監聽器上面講解了有兩種方式。事件的發布可以通過 ApplicationEventPublisher.publishEvent() 方法。此處演示直接用 configurableApplicationContext 發布,它實現了 ApplicationEventPublisher 接口。

package com.chenpi;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplicationpublic class Application { public static void main(String[] args) {// SpringApplication.run(Application.class, args);// 注冊監聽器SpringApplication app = new SpringApplicationBuilder(Application.class).listeners(new MyApplicationListener()).build();ConfigurableApplicationContext configurableApplicationContext = app.run(args);// 方便演示,在項目啟動后發布事件,當然也可以在其他操作和其他時間點發布事件configurableApplicationContext.publishEvent(new MyApplicationEvent('我是事件源,項目啟動成功后發布事件', '我是自定義事件屬性')); }}

啟動服務,結果顯示確實監聽到發布的事件了。

2021-06-26 16:15:09.584  INFO 10992 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ’’

2021-06-26 16:15:09.601  INFO 10992 --- [           main] com.chenpi.Application                   : Started Application in 2.563 seconds (JVM running for 4.012)

2021-06-26 16:15:09.606  INFO 10992 --- [           main] com.chenpi.MyApplicationListener         : >>> MyApplicationListener:MyApplicationEvent{myField=’我是自定義事件屬性’, source=我是事件源,項目啟動成功后發布事件}

事件監聽機制能達到分發,解耦效果。例如可以在業務類中發布事件,讓監聽在此事件的監聽器執行自己的業務處理。例如:

package com.chenpi;import org.springframework.context.ApplicationEventPublisher;import org.springframework.context.ApplicationEventPublisherAware;import org.springframework.stereotype.Service;@Servicepublic class MyService implements ApplicationEventPublisherAware { private ApplicationEventPublisher applicationEventPublisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher; } public void testEvent() {applicationEventPublisher.publishEvent(new MyApplicationEvent('我是事件源', '我是自定義事件屬性')); }}五、注解式監聽器

除了實現 ApplicationListener 接口創建監聽器外,Spring 還提供了注解 @EventListener 來創建監聽器。

package com.chenpi;import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Slf4j@Componentpublic class MyApplicationListener01 { @EventListener public void onApplicationEvent(MyApplicationEvent event) {log.info('>>> MyApplicationListener:{}', event); }}

而且注解還可以通過條件過濾只監聽指定條件的事件。例如事件的 myField 屬性的值等于'陳皮'的事件。

package com.chenpi;import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Slf4j@Componentpublic class MyApplicationListener01 { @EventListener(condition = '#event.myField.equals(’陳皮’)') public void onApplicationEvent(MyApplicationEvent event) {log.info('>>> MyApplicationListener:{}', event); }}

還可以在同一個類中定義多個監聽,對同一個事件的不同監聽還可以指定順序。order 值越小越先執行。

package com.chenpi;import org.springframework.context.event.EventListener;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Slf4j@Componentpublic class MyApplicationListener01 { @Order(2) @EventListener public void onApplicationEvent(MyApplicationEvent event) {log.info('>>> onApplicationEvent order=2:{}', event); } @Order(1) @EventListener public void onApplicationEvent01(MyApplicationEvent event) {log.info('>>> onApplicationEvent order=1:{}', event); } @EventListener public void otherEvent(YourApplicationEvent event) {log.info('>>> otherEvent:{}', event); }}

執行結果如下:

>>> onApplicationEvent order=1:MyApplicationEvent{myField=’陳皮’, source=我是事件源}

>>> onApplicationEvent order=2:MyApplicationEvent{myField=’陳皮’, source=我是事件源}

>>> otherEvent:MyApplicationEvent{myField=’我是自定義事件屬性01’, source=我是事件源01}

事件的監聽處理是同步的,如下:

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.context.ApplicationEventPublisher;import org.springframework.context.ApplicationEventPublisherAware;import org.springframework.stereotype.Service;@Service@Slf4jpublic class MyService implements ApplicationEventPublisherAware { private ApplicationEventPublisher applicationEventPublisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher; } public void testEvent() {log.info('>>> testEvent begin');applicationEventPublisher.publishEvent(new MyApplicationEvent('我是事件源', '陳皮'));applicationEventPublisher.publishEvent(new YourApplicationEvent('我是事件源01', '我是自定義事件屬性01'));log.info('>>> testEvent end'); }}

執行結果如下:

2021-06-26 20:34:27.990  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyService                     : >>> testEvent begin

2021-06-26 20:34:27.990  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyApplicationListener01       : >>> onApplicationEvent order=1:MyApplicationEvent{myField=’陳皮’, source=我是事件源}

2021-06-26 20:34:27.991  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyApplicationListener01       : >>> onApplicationEvent order=2:MyApplicationEvent{myField=’陳皮’, source=我是事件源}

2021-06-26 20:34:27.992  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyApplicationListener01       : >>> otherEvent:MyApplicationEvent{myField=’我是自定義事件屬性01’, source=我是事件源01}

2021-06-26 20:34:27.992  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyService                     : >>> testEvent end

不過,我們也可以顯示指定異步方式去執行監聽器,記得在服務添加 @EnableAsync 注解開啟異步注解。

package com.chenpi;import org.springframework.context.event.EventListener;import org.springframework.core.annotation.Order;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Slf4j@Componentpublic class MyApplicationListener01 { @Async @Order(2) @EventListener public void onApplicationEvent(MyApplicationEvent event) {log.info('>>> onApplicationEvent order=2:{}', event); } @Order(1) @EventListener public void onApplicationEvent01(MyApplicationEvent event) {log.info('>>> onApplicationEvent order=1:{}', event); } @Async @EventListener public void otherEvent(YourApplicationEvent event) {log.info('>>> otherEvent:{}', event); }}

執行結果如下,注意打印的線程名。

2021-06-26 20:37:04.807  INFO 9092 --- [nio-8081-exec-1] com.chenpi.MyService                     : >>> testEvent begin

2021-06-26 20:37:04.819  INFO 9092 --- [nio-8081-exec-1] com.chenpi.MyApplicationListener01       : >>> onApplicationEvent order=1:MyApplicationEvent{myField=’陳皮’, source=我是事件源}

2021-06-26 20:37:04.831  INFO 9092 --- [         task-1] com.chenpi.MyApplicationListener01       : >>> onApplicationEvent order=2:MyApplicationEvent{myField=’陳皮’, source=我是事件源}

2021-06-26 20:37:04.831  INFO 9092 --- [nio-8081-exec-1] com.chenpi.MyService                     : >>> testEvent end

2021-06-26 20:37:04.831  INFO 9092 --- [         task-2] com.chenpi.MyApplicationListener01       : >>> otherEvent:MyApplicationEvent{myField=’我是自定義事件屬性01’, source=我是事件源01}

以上就是詳解Spring事件發布與監聽機制的詳細內容,更多關于Spring事件發布與監聽機制的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
主站蜘蛛池模板: 篷房|仓储篷房|铝合金篷房|体育篷房|篷房厂家-华烨建筑科技官网 知名电动蝶阀,电动球阀,气动蝶阀,气动球阀生产厂家|价格透明-【固菲阀门官网】 | 银川美容培训-美睫美甲培训-彩妆纹绣培训-新娘化妆-学化妆-宁夏倍莱妮职业技能培训学校有限公司 临时厕所租赁_玻璃钢厕所租赁_蹲式|坐式厕所出租-北京慧海通 | 超声波破碎仪-均质乳化机(供应杭州,上海,北京,广州,深圳,成都等地)-上海沪析实业有限公司 | 拉力机-拉力试验机-万能试验机-电子拉力机-拉伸试验机-剥离强度试验机-苏州皖仪实验仪器有限公司 | 洁净化验室净化工程_成都实验室装修设计施工_四川华锐净化公司 | 青岛代理记账_青岛李沧代理记账公司_青岛崂山代理记账一个月多少钱_青岛德辉财税事务所官网 | 防爆暖风机_防爆电暖器_防爆电暖风机_防爆电热油汀_南阳市中通智能科技集团有限公司 | 木材烘干机,木炭烘干机,纸管/佛香烘干设备-河南蓝天机械制造有限公司 | 江苏农村商业银行招聘网_2024江苏农商行考试指南_江苏农商行校园招聘 | 香蕉筛|直线|等厚|弧形|振动筛|香蕉筛厂家-洛阳隆中重工 | ◆大型吹塑加工|吹塑加工|吹塑代加工|吹塑加工厂|吹塑设备|滚塑加工|滚塑代加工-莱力奇塑业有限公司 | 整车VOC采样环境舱-甲醛VOC预处理舱-多舱法VOC检测环境仓-上海科绿特科技仪器有限公司 | 黑龙江京科脑康医院-哈尔滨精神病医院哪家好_哈尔滨精神科医院排名_黑龙江精神心理病专科医院 | 全自动过滤器_反冲洗过滤器_自清洗过滤器_量子除垢环_量子环除垢_量子除垢 - 安士睿(北京)过滤设备有限公司 | LED灯杆屏_LED广告机_户外LED广告机_智慧灯杆_智慧路灯-太龙智显科技(深圳)有限公司 | 【星耀裂变】_企微SCRM_任务宝_视频号分销裂变_企业微信裂变增长_私域流量_裂变营销 | 洛阳防爆合格证办理-洛阳防爆认证机构-洛阳申请国家防爆合格证-洛阳本安防爆认证代办-洛阳沪南抚防爆电气技术服务有限公司 | 快干水泥|桥梁伸缩缝止水胶|伸缩缝装置生产厂家-广东广航交通科技有限公司 | 空心明胶胶囊|植物胶囊|清真胶囊|浙江绿键胶囊有限公司欢迎您! | SMN-1/SMN-A ABB抽屉开关柜触头夹紧力检测仪-SMN-B/SMN-C-上海徐吉 | 千斤顶,液压千斤顶-力良企业,专业的液压千斤顶制造商,shliliang.com | MVR蒸发器厂家-多效蒸发器-工业废水蒸发器厂家-康景辉集团官网 | 气体热式流量计-定量控制流量计(空气流量计厂家)-湖北南控仪表科技有限公司 | 深圳工程师职称评定条件及流程_深圳职称评审_职称评审-职称网 | 通信天线厂家_室分八木天线_对数周期天线_天线加工厂_林创天线源头厂家 | 涿州网站建设_网站设计_网站制作_做网站_固安良言多米网络公司 | 乐之康护 - 专业护工服务平台,提供医院陪护-居家照护-居家康复 | 钢结构厂房造价_钢结构厂房预算_轻钢结构厂房_山东三维钢结构公司 | 地图标注-手机导航电子地图如何标注-房地产商场地图标记【DiTuBiaoZhu.net】 | 小型气象站_便携式自动气象站_校园气象站-竞道气象设备网 | 杭州中央空调维修_冷却塔/新风机柜/热水器/锅炉除垢清洗_除垢剂_风机盘管_冷凝器清洗-杭州亿诺能源有限公司 | 胜为光纤光缆_光纤跳线_单模尾纤_光纤收发器_ODF光纤配线架厂家直销_北京睿创胜为科技有限公司 - 北京睿创胜为科技有限公司 | 安徽净化板_合肥岩棉板厂家_玻镁板厂家_安徽科艺美洁净科技有限公司 | 冷水机,风冷冷水机,水冷冷水机,螺杆冷水机专业制造商-上海祝松机械有限公司 | 包装设计公司,产品包装设计|包装制作,包装盒定制厂家-汇包装【官方网站】 | 河南砖机首页-全自动液压免烧砖机,小型砌块水泥砖机厂家[十年老厂] | 山东钢衬塑罐_管道_反应釜厂家-淄博富邦滚塑防腐设备科技有限公司 | 郑州大巴车出租|中巴车租赁|旅游大巴租车|包车|郑州旅游大巴车租赁有限公司 | 雷冲击高压发生器-水内冷直流高压发生器-串联谐振分压器-武汉特高压电力科技有限公司 | 【德信自动化】点胶机_全自动点胶机_自动点胶机厂家_塑料热压机_自动螺丝机-深圳市德信自动化设备有限公司 | 啤酒设备-小型啤酒设备-啤酒厂设备-济南中酿机械设备有限公司 |