SpringBoot實(shí)現(xiàn)自定義事件的方法詳解
簡介
說明
本文用實(shí)例來介紹如何在SpringBoot中自定義事件來使用觀察者模式。
事件的順序
可使用實(shí)現(xiàn)Ordered接口的方式,調(diào)整監(jiān)聽器順序。
注意:必須是同時(shí)實(shí)現(xiàn) ApplicationListener<MyEvent>,Ordered這樣的方法才能控制順序。
下邊幾種都是無法控制順序的:
- @Component+@EventListerner+實(shí)現(xiàn)Ordered
- 實(shí)現(xiàn) ApplicationListener<MyEvent>+@Order
步驟1:自定義事件
通過繼承ApplicationEvent來自定義事件。
構(gòu)造器的參數(shù)為該事件的相關(guān)數(shù)據(jù)對象,監(jiān)聽器可以獲取到該數(shù)據(jù)對象,進(jìn)而進(jìn)行相關(guān)邏輯處理。
package com.example.event;
import org.springframework.context.ApplicationEvent;
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
步驟2:自定義監(jiān)聽器
方案1:ApplicationListener
法1:@EventListener
監(jiān)聽單個(gè)事件
package com.example.event;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
public class MyListener {
@EventListener
public void abc(MyEvent event) {
System.out.println("監(jiān)聽器: " + "MyListener");
System.out.println(" 線程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的數(shù)據(jù):" + event.getSource());
}
}
或者
package com.example.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
public class MyListener {
@EventListener({MyEvent.class})
public void abc(ApplicationEventevent) {
System.out.println("監(jiān)聽器: " + "MyListener");
System.out.println(" 線程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的數(shù)據(jù): " + event.getSource());
}
}
上邊的辦法比較好,因?yàn)椴恍枰愋娃D(zhuǎn)換了。直接就能確定是MyEvent類型。
監(jiān)聽多個(gè)事件
事件進(jìn)來之后,可以使用if(event instanceOf MyEvent.class)來判斷是哪種事件。
package com.example.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener {
@EventListener({MyEvent.class, MyEvent2.class})
public void abc(ApplicationEvent event) {
System.out.println("監(jiān)聽器: " + "MyListener");
System.out.println(" 所在線程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的數(shù)據(jù):" + event.getSource());
}
}
監(jiān)聽所有ApplicationEvent
若使用這種寫法,啟動時(shí)會打印很多Spring自帶的事件。任意ApplicationEvent都會進(jìn)入這里邊。
package com.example.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener {
@EventListener
public void abc(ApplicationEvent event) {
System.out.println("監(jiān)聽器: " + "MyListener");
System.out.println(" 所在線程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的數(shù)據(jù):" + event.getSource());
}
}
法2:實(shí)現(xiàn)ApplicationListener<T>接口
public class MyListener implements ApplicationListener<MyEvent>{
public void onApplicationEvent(MyEvent event){
System.out.println("監(jiān)聽器: " + "MyListener");
System.out.println(" 所在線程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的數(shù)據(jù):" + event.getSource());
}
}
方案2:SmartApplicationListener
源碼如下
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
boolean supportsEventType(Class<? extends ApplicationEvent> var1);
default boolean supportsSourceType(@Nullable Class<?> sourceType) {
return true;
}
default int getOrder() {
return 2147483647;
}
}
supportsEventType:支持的事件的類型
supportsSourceType:支持的數(shù)據(jù)的類型
getOrder:2147483641:是2^31-1,也就是32位的int的最大正數(shù) 。
示例
事件
package com.example.event;
import org.springframework.context.ApplicationEvent;
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
監(jiān)聽器1
package com.example.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
return aClass == MyEvent.class;
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType == String.class;
}
@Override
public int getOrder() {
return 2;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("監(jiān)聽器: " + "MyListener");
System.out.println(" 所在線程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的數(shù)據(jù):" + event.getSource());
System.out.println(" 是MyEvent?:" + (event instanceof MyEvent));
}
}
監(jiān)聽器2
package com.example.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener2 implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
return aClass == MyEvent.class;
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return sourceType == String.class;
}
@Override
public int getOrder() {
return 1;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("監(jiān)聽器: " + "MyListener2");
System.out.println(" 所在線程: " + Thread.currentThread().getName());
System.out.println(" 事件: " + event);
System.out.println(" 事件的數(shù)據(jù):" + event.getSource());
System.out.println(" 是MyEvent?:" + (event instanceof MyEvent));
}
}
發(fā)布器
package com.example.event;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class MyPublisher {
@Autowired
ApplicationContext applicationContext;
public void myPublish(String message) {
System.out.println("發(fā)布器所在線程:" + Thread.currentThread().getName());
applicationContext.publishEvent(new MyEvent(message));
}
}
測試
package com.example.controller;
import com.example.event.MyPublisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
MyPublisher myPublisher;
@GetMapping("/test1")
public String test1() {
myPublisher.myPublish("Hello");
return "test1 success";
}
}
啟動后,訪問:http://localhost:8080/test1
后端輸出:
發(fā)布器所在線程:http-nio-8080-exec-2
監(jiān)聽器: MyListener2
所在線程: http-nio-8080-exec-2
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
是MyEvent?:true
監(jiān)聽器: MyListener
所在線程: http-nio-8080-exec-2
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
是MyEvent?:true
如果將監(jiān)聽器的實(shí)現(xiàn)的Ordered順序顛倒,則輸出結(jié)果如下:
發(fā)布器所在線程:http-nio-8080-exec-1
監(jiān)聽器: MyListener
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
是MyEvent?:true
監(jiān)聽器: MyListener2
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
是MyEvent?:true
步驟3:注冊監(jiān)聽器
| 方式 | 適用范圍 | 能否搭配@Async注解,進(jìn)行異步監(jiān)聽 |
|---|---|---|
| @Component | 所有監(jiān)聽器 | 能 |
| application.yml中添加配置 | 實(shí)現(xiàn)ApplicationListener<T>接口的監(jiān)聽器 | 不能 |
| 啟動類中注冊 | 實(shí)現(xiàn)ApplicationListener<T>接口的監(jiān)聽器 | 不能 |
法1:@Component(適用于所有監(jiān)聽器)
package com.example.event;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener {
@EventListener
public void abc(MyEvent event) {
System.out.println("監(jiān)聽器:" + "MyListener");
System.out.println("線程:" + Thread.currentThread().getName());
System.out.println("事件:" + event);
System.out.println("事件的數(shù)據(jù):" + event.getSource());
}
}
package com.example.event;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyListener2 implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("監(jiān)聽器:" + "MyListener2");
System.out.println("線程:" + Thread.currentThread().getName());
System.out.println("事件:" + event);
System.out.println("事件的數(shù)據(jù):" + event.getSource());
}
}
法2:application.yml中添加配置
只適用于實(shí)現(xiàn)ApplicationListener<T>接口的監(jiān)聽器
context:
listener:
classes: com.example.event.MyListener,com.example.event.MyListener2
法3:啟動類中注冊
只適用于實(shí)現(xiàn)ApplicationListener<T>接口的監(jiān)聽器
package com.example;
import com.example.event.MyListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 原來是這樣的:SpringApplication.run(DemoApplication.class, args);
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
context.addApplicationListener(new MyListener());
}
}
步驟4:發(fā)布事件
法1:注入ApplicationContext,調(diào)用其publishEvent方法
package com.example.event;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class MyPublisher {
@Autowired
ApplicationContext applicationContext;
public void myPublish(String message) {
applicationContext.publishEvent(new MyEvent(message));
}
}
法2:啟動類中發(fā)布
package com.example;
import com.example.event.MyEvent;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//原來是:SpringApplication.run(DemoApplication.class, args);
ConfigurableApplicationContext context =SpringApplication.run(DemoApplication.class, args);
context.publishEvent(new MyEvent("Hello"));
}
}以上就是SpringBoot實(shí)現(xiàn)自定義事件的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot自定義事件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)MySQL數(shù)據(jù)實(shí)時(shí)同步至Elasticsearch的方法詳解
MySQL擅長事務(wù)處理,而Elasticsearch(ES)則專注于搜索與分析,將MySQL數(shù)據(jù)實(shí)時(shí)同步到ES,可以充分發(fā)揮兩者的優(yōu)勢,下面我們就來看看如何使用Java實(shí)現(xiàn)這一功能吧2025-03-03
Spring中Websocket身份驗(yàn)證和授權(quán)的實(shí)現(xiàn)
在Web應(yīng)用開發(fā)中,安全一直是非常重要的一個(gè)方面,本文主要介紹了Spring中Websocket身份驗(yàn)證和授權(quán)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08
Java多線程編程之讀寫鎖ReadWriteLock用法實(shí)例
這篇文章主要介紹了Java多線程編程之讀寫鎖ReadWriteLock用法實(shí)例,本文直接給出編碼實(shí)例,需要的朋友可以參考下2015-05-05
MyBatis與SpringMVC相結(jié)合實(shí)現(xiàn)文件上傳、下載功能
這篇文章主要介紹了MyBatis與SpringMVC相結(jié)合實(shí)現(xiàn)文件上傳、下載功能的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06
SpringBoot中application.yml基本配置解讀
文章主要介紹了Spring Boot項(xiàng)目中`application.properties`和`application.yml`配置文件的使用方法和區(qū)別,包括優(yōu)先級、配置文件所在目錄、端口服務(wù)配置、數(shù)據(jù)庫配置、多profile配置以及靜態(tài)資源路徑的指定2024-12-12
springcloud使用profile實(shí)現(xiàn)多環(huán)境配置方式
這篇文章主要介紹了springcloud使用profile實(shí)現(xiàn)多環(huán)境配置方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03

