成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入淺出Spring/SpringBoot 事件監聽機制

安全 應用安全
在Java中,事件對象都是繼承java.util.EventObject對象,事件監聽器都是java.util.EventListener實例,EventObject對象不提供默認構造器,需要外部傳遞source參數,即用于記錄并跟蹤事件的來源。

[[327899]]

說明

事件監聽機制可以理解為是一種觀察者模式,有數據發布者(事件源)和數據接受者(監聽器);

在Java中,事件對象都是繼承java.util.EventObject對象,事件監聽器都是java.util.EventListener實例;

EventObject對象不提供默認構造器,需要外部傳遞source參數,即用于記錄并跟蹤事件的來源;

Spring事件

Spring事件對象為ApplicationEvent,繼承EventObject,源碼如下:

  1. public abstract class ApplicationEvent extends EventObject { 
  2.  
  3.     /** 
  4.      * Create a new ApplicationEvent. 
  5.      * @param source the object on which the event initially occurred (never {@code null}) 
  6.      */ 
  7.     public ApplicationEvent(Object source) { 
  8.         super(source); 
  9.         this.timestamp = System.currentTimeMillis(); 
  10.     } 
  11.  

Spring事件監聽器為ApplicationListener,繼承EventListener, 源碼如下:

  1. public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { 
  2.     void onApplicationEvent(E var1); 

實現Spring事件監聽有兩種方式:

  1. 面向接口編程,實現ApplicationListener接口;
  2. 基于注解驅動,@EventListener(Spring自定義的注解);

實例:

面向接口編程,實現ApplicationListener接口:

自定義事件對象:

  1. public class MyApplicationEvent extends ApplicationEvent { 
  2.     public MyApplicationEvent(Object source) { 
  3.         super(source); 
  4.     } 

自定義事件監聽器:

  1. public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> { 
  2.     @Override 
  3.     public void onApplicationEvent(MyApplicationEvent event) { 
  4.         System.out.println("收到事件:" + event); 
  5.     } 

啟動服務并發布事件:

  1. public class ApplicationEventBootstrap { 
  2.  
  3.     public static void main(String[] args) { 
  4.         AnnotationConfigApplicationContext context = 
  5.                 new AnnotationConfigApplicationContext(); 
  6.         // 注冊自定義事件監聽器 
  7.         context.addApplicationListener(new MyApplicationListener()); 
  8.         // 啟動上下文 
  9.         context.refresh(); 
  10.         // 發布事件,事件源為Context 
  11.         context.publishEvent(new MyApplicationEvent(context)); 
  12.         // 結束 
  13.         context.close(); 
  14.     } 

運行結果:

  1. 收到事件:com.xx.MyApplicationEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@cb0ed20, started on Sat May 16 16:32:04 CST 2020] 

使用注解 @EventListener實現Spring事件監聽:

  1. @Component 
  2. public class MyApplicationListener2 { 
  3.  
  4.     @EventListener(MyApplicationEvent.class) 
  5.     public void onEvent(MyApplicationEvent event) { 
  6.         System.out.println("收到事件:" + event); 
  7.     } 

啟動并發布事件:

  1. public class ApplicationEventBootstrap { 
  2.  
  3.     public static void main(String[] args) { 
  4.         AnnotationConfigApplicationContext context = 
  5.                 new AnnotationConfigApplicationContext(); 
  6.         // 注冊自定義事件監聽器 
  7.         context.register(MyApplicationListener2.class); 
  8.         // 啟動上下文 
  9.         context.refresh(); 
  10.         // 發布事件,事件源為Context 
  11.         context.publishEvent(new MyApplicationEvent(context)); 
  12.         // 結束 
  13.         context.close(); 
  14.     } 

運行結果:

  1. 收到事件:com.xx.MyApplicationEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@cb0ed20, started on Sat May 16 16:32:04 CST 2020] 

通過實例可以看出,上面兩種方式都可正常發布和接收事件。

實現原理

通過上面實例可以看出,context 可以發布事件,那底層是怎么發布的,讓我們繼續看源碼:

  1. public abstract class AbstractApplicationContext extends DefaultResourceLoader 
  2.         implements ConfigurableApplicationContext { 
  3.       protected void publishEvent(Object event, @Nullable ResolvableType eventType) { 
  4.         ... 
  5.         getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); 
  6.         ... 
  7.       } 

通過源碼我們可以看出,事件應該是通過

ApplicationEventMulticaster發布的,我們繼續看:

  1. public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster 

Spring 中事件發布都是通過

SimpleApplicationEventMulticaster來實現的

  1. public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { 
  2.         ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); 
  3.         for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { 
  4.             Executor executor = getTaskExecutor(); 
  5.             if (executor != null) { 
  6.         // 異步 
  7.                 executor.execute(() -> invokeListener(listener, event)); 
  8.             } 
  9.             else { 
  10.                 invokeListener(listener, event); 
  11.             } 
  12.         } 
  13.     } 

可以看出,如果設置了Executor則異步發送,否則同步;而且可以看出通過 resolveDefaultEventType(event) 對發布的事件類型進行了校驗,這就是為什么我們可以直接使用泛型來指定我們想接收的事件對象, 比如上面的 ApplicationListener。

  1. private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { 
  2.         try { 
  3.             listener.onApplicationEvent(event); 
  4.          

最后就使用對應的ApplicationListener進行接收和處理就行了,那么ApplicationListener是什么時候注冊的呢?

如何添加ApplicationListener?

  1. 直接添加,使用content.addApplicationListener(上面實例中有使用);
  2. 將自定義的ApplicationListener注冊為一個Bean,Spring再初始化Bean之后會添加,具體代碼在ApplicationListenerDetector#postProcessAfterInitialization,判斷一個Bean如果是ApplicationListener,則也是使用context.addApplicationListener添加;
  3. 使用注解@EventListener,在初始化Bean之后,會在EventListenerMethodProcessor中進行處理和添加;

第三種實現的源碼如下(

EventListenerMethodProcessor中):

  1. private void processBean(final String beanName, final Class<?> targetType) { 
  2.   .... 
  3.   // 獲取public 且有@EventListener的方法  
  4.   AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class)); 
  5.   ...  
  6.   ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse);                  
  7.   // 添加監聽器 
  8.   context.addApplicationListener(applicationListener);  

Spring內建事件

  • ContextRefreshedEvent: Spring應用上下文就緒事件;
  • ContextStartedEvent: Spring應用上下文啟動事件;
  • ContextStopedEvent: Spring應用上下文停止事件;
  • ContextClosedEvent: Spring應用上下文關閉事件;

Spring Boot事件

Spring Boot事件是在Spring事件基礎上進行的封裝

  1. public abstract class SpringApplicationEvent extends ApplicationEvent 

事件對象改為SpringApplicationEvent,事件源為SpringApplication(Spring事件源為Context);

底層發布事件還是使用

SimpleApplicationEventMulticaster 對象,不過有點需要說明的是,Spring Boot 1.4開始,SpringApplication和ApplicationContext使用的都是

SimpleApplicationEventMulticaster實例,但是兩者屬于不同的對象(1.0 ~ 1.3版本是同一個對象);

事件回顧:

  1. public class EventBootstrap { 
  2.  
  3.     public static void main(String[] args) { 
  4.         new SpringApplicationBuilder(Object.class) 
  5.                 .listeners(event -> { 
  6.                     System.out.println("事件對象:" 
  7.                     + event.getClass().getSimpleName() 
  8.                     + " ,事件源:" + event.getSource().getClass().getSimpleName()); 
  9.                 }) 
  10.                 .web(WebApplicationType.NONE) 
  11.                 .run(args) 
  12.                 .close(); 
  13.     } 

運行結果:

  1. 事件對象:ApplicationContextInitializedEvent ,事件源:SpringApplication 
  2. 事件對象:ApplicationPreparedEvent ,事件源:SpringApplication 
  3. 事件對象:ContextRefreshedEvent ,事件源:AnnotationConfigApplicationContext 
  4. 事件對象:ApplicationStartedEvent ,事件源:SpringApplication 
  5. 事件對象:ApplicationReadyEvent ,事件源:SpringApplication 
  6. 事件對象:ContextClosedEvent ,事件源:AnnotationConfigApplicationContext 

從結果可以看出,事件對象類型和事件源,以及事件發布順序。

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2016-10-14 14:32:58

JavascriptDOMWeb

2016-10-14 13:53:05

JavascriptDOMWeb

2025-03-27 09:38:35

2021-03-16 08:54:35

AQSAbstractQueJava

2011-07-04 10:39:57

Web

2022-01-12 08:54:52

Spring編程架構設計

2023-11-12 00:10:07

Redis高可用

2019-01-07 15:29:07

HadoopYarn架構調度器

2017-07-02 18:04:53

塊加密算法AES算法

2012-05-21 10:06:26

FrameworkCocoa

2021-07-20 15:20:02

FlatBuffers阿里云Java

2022-09-26 09:01:15

語言數據JavaScript

2022-09-29 09:19:04

線程池并發線程

2011-01-27 10:11:46

J2EEjavaspring

2025-05-09 01:30:00

JavaScript事件循環基石

2018-01-25 18:30:09

Zookeeper分布式數據

2009-11-30 16:46:29

學習Linux

2012-02-21 13:55:45

JavaScript

2022-01-11 07:52:22

CSS 技巧代碼重構

2018-11-09 16:24:25

物聯網云計算云系統
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲精品美女 | 中文字幕日本一区二区 | 日韩精品一区二区三区 | 亚洲综合无码一区二区 | 97av视频在线 | 夜夜骚视频 | 91精品国产91久久久久久密臀 | 精品久久中文字幕 | 四虎永久免费黄色影片 | 亚洲精品乱码久久久久久按摩观 | 一级毛片免费视频观看 | 91中文在线观看 | 国产成人精品一区二 | 超碰520 | 蜜臀网 | 亚洲人成人一区二区在线观看 | 亚洲第一天堂无码专区 | 日日日日日日bbbbb视频 | 天堂网中文 | 少妇特黄a一区二区三区88av | 狠狠亚洲 | 日韩精品免费一区 | 一区二区蜜桃 | 国产精品mv在线观看 | 91精品国产综合久久久动漫日韩 | 色婷婷亚洲 | 一区中文字幕 | 久久99精品久久 | 精品一区二区久久 | 狠狠久久综合 | 亚洲成人av | 精品国产区 | 91精品一区二区三区久久久久久 | 五月激情婷婷网 | 自拍视频在线观看 | 亚洲第1页 | 91久久久久久久久久久久久 | 最新91在线 | av大片在线观看 | 日韩综合在线 | 亚洲一区国产精品 |