詳解Spring中的Event事件處理機制和原理


我們都知道 Spring 的核心是 ApplicationContext,它負責管理 bean 的完整生命周期。當spring加載 bean 時,ApplicationContext 會發布某些類型的事件。例如,當上下文啟動時,會發布ContextStartedEvent,當上下文停止時,會發布ContextStoppedEvent。

Spring里的5種標准事件

上下文更新事件(ContextRefreshedEvent) 在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發
上下文開始事件(ContextStartedEvent) 當容器調用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發該事件
上下文停止事件(ContextStoppedEvent) 當容器調用ConfigurableApplicationContext的Stop()方法停止容器時觸發該事件
上下文關閉事件(ContextClosedEvent) 當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的所有單例Bean都被銷毀
請求處理事件(RequestHandledEvent) 在Web應用中,當一個http請求(request)結束觸發該事件

如果一個bean實現了ApplicationListener接口,當一個ApplicationEvent 被發布以后,bean會自動被通知。

注意:由於 Spring 的事件處理是單線程的,所以如果一個事件被發布,直至並且除非所有的接收者得到的該消息,該進程被阻塞並且流程將不會繼續。因此,如果事件處理被使用,在設計應用程序時應注意。

好處

Spring的事件通知機制是一項很有用的功能,使用事件機制我們可以將相互耦合的代碼解耦,從而方便功能的修改與添加。

示例

除了上面介紹的5個spring已經幫我們實現的事件,我們還可以實現自定義事件。

舉個例子,假設有一個添加評論的方法,在評論添加成功之后需要進行修改redis緩存、給用戶添加積分等等操作。當然可以在添加評論的代碼后面假設這些操作,但是這樣的代碼違反了設計模式的多項原則:單一職責原則、迪米特法則、開閉原則。一句話說就是耦合性太大了,比如將來評論添加成功之后還需要有另外一個操作,這時候我們就需要去修改我們的添加評論代碼了。

自定義事件類

事件監聽類

事件發布類

測試類

結果

Spring Event事件通知原理

首先我們跟蹤publishEvent方法,這個方法在AbstractApplicationContext類中。

經過上面的分析,我們看到事件是通過applicationEventMulticaster來廣播出去的。

applicationEventMulticaster在Spring的啟動過程中被建立,在Spring的啟動過程中,在核心方法refresh中建立applicationEventMulticaster:

關注initApplicationEventMulticaster和registerListeners方法。

經過前面的分析,我們知道了事件廣播器applicationEventMulticaster如何被構建,下面我們分析事件的廣播過程。

經過上面的分析,我們知道了Spring如何發送並響應事件。下面我們來分析如何使Spring能夠異步響應事件。

異步響應Event

默認情況下,Spring是同步執行Event的響應方法的。如果響應方法的執行時間很長會阻塞發送事件的方法,因此很多場景下,我們需要讓事件的響應異步化。

自定義SimpleApplicationEventMulticaster

通過前面的代碼分析,我們發現如果SimpleApplicationEventMulticaster中的taskExecutor如果不為null,將在taskExecutor中異步執行響應程序。

applicationEventMulticaster的新建在initApplicationEventMulticaster方法中,默認情況下它會新建一個SimpleApplicationEventMulticaster,其中的taskExecutor為null。因此想要taskExecutor不為null,我們可以自己手動創建一個SimpleApplicationEventMulticaster然后設置一個taskExecutor。

添加AsyncTaskConfig配置類

此時再次執行程序,執行結果如下:

可以看到這邊是在新線程TaskExecutor-13里執行的,而不是像上面那樣在main主線程里執行的。

@Async原理

@Async注解可以將方法異步化,下面我們來看看它的原理是什么。

我們在Config類中添加了@EnableAsync注釋。@EnableAsync注釋引入AsyncConfigurationSelector類,AsyncConfigurationSelector類導入ProxyAsyncConfiguration類,ProxyAsyncConfiguration類新建過程中會新建AsyncAnnotationBeanPostProcessor。

AsyncAnnotationBeanPostProcessor類繼承了BeanPostProcessor,當每個Bean新建完成后會調用AsyncAnnotationBeanPostProcessor的postProcessAfterInitialization方法:

postProcessAfterInitialization方法判斷bean是否符合要求(方法上是否加了@Async注釋),如果符合要求則對bean加上代理,代理類為AnnotationAsyncExecutionInterceptor。

調用我們的方法時首先調用AnnotationAsyncExecutionInterceptor的invoke方法,invoke方法將我們真正的方法包裝成一個Callable任務,將這個任務提交到executor中執行。由此達到了將我們的方法異步化的目的。

總結

Spring的事件機制是一套相當靈活的機制,使用它可以簡便地將我們的代碼解耦從而優化我們的代碼。經過前面的分析我們了解了其中的運行原理,這有助於我們更好地使用這套機制。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM