SpringBoot實現(xiàn)自定義事件的方法詳解
簡介
說明
本文用實例來介紹如何在SpringBoot中自定義事件來使用觀察者模式。
事件的順序
可使用實現(xiàn)Ordered接口的方式,調(diào)整監(jiān)聽器順序。
注意:必須是同時實現(xiàn) ApplicationListener<MyEvent>,Ordered這樣的方法才能控制順序。
下邊幾種都是無法控制順序的:
- @Component+@EventListerner+實現(xiàn)Ordered
- 實現(xiàn) ApplicationListener<MyEvent>+@Order
步驟1:自定義事件
通過繼承ApplicationEvent來自定義事件。
構造器的參數(shù)為該事件的相關數(shù)據(jù)對象,監(jiān)聽器可以獲取到該數(shù)據(jù)對象,進而進行相關邏輯處理。
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)聽單個事件
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()); } }
上邊的辦法比較好,因為不需要類型轉(zhuǎn)換了。直接就能確定是MyEvent類型。
監(jiā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
若使用這種寫法,啟動時會打印很多Spring自帶的事件。任意ApplicationEvent都會進入這里邊。
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:實現(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)聽器的實現(xiàn)的Ordered順序顛倒,則輸出結果如下:
發(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注解,進行異步監(jiān)聽 |
---|---|---|
@Component | 所有監(jiān)聽器 | 能 |
application.yml中添加配置 | 實現(xiàn)ApplicationListener<T>接口的監(jiān)聽器 | 不能 |
啟動類中注冊 | 實現(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中添加配置
只適用于實現(xiàn)ApplicationListener<T>接口的監(jiān)聽器
context:
listener:
classes: com.example.event.MyListener,com.example.event.MyListener2
法3:啟動類中注冊
只適用于實現(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實現(xiàn)自定義事件的方法詳解的詳細內(nèi)容,更多關于SpringBoot自定義事件的資料請關注腳本之家其它相關文章!
相關文章
深入解析反編譯字節(jié)碼文件中的代碼邏輯JVM中的String操作
這篇文章主要介紹了深入解析反編譯字節(jié)碼文件中的代碼邏輯JVM中的String操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10Java深入學習圖形用戶界面GUI之創(chuàng)建窗體
圖形編程中,窗口是一個重要的概念,窗口其實是一個矩形框,應用程序可以使用其從而達到輸出結果和接受用戶輸入的效果,學習了GUI就讓我們用它來創(chuàng)建一個窗體2022-05-05