【Spring】9、Spring中的事件Event


Spring的ApplicationContext 提供了支持事件和代碼中監聽器的功能。

我們可以創建bean用來監聽在ApplicationContext 中發布的事件。ApplicationEvent類和在ApplicationContext接口中處理的事件,如果一個bean實現了ApplicationListener接口,當一個ApplicationEvent 被發布以后,bean會自動被通知。

1
2
3
4
5
6
7
8
public class AllApplicationEventListener implements ApplicationListener < ApplicationEvent >
{
     @Override
     public void onApplicationEvent(ApplicationEvent applicationEvent)
     {
         //process event
     }
}

Spring 提供了以下5中標准的事件:

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

應用場景:很多時候我們想要在某個類加載完畢時干某件事情,但是使用了spring管理對象,我們這個類引用了其他類(可能是更復雜的關聯),所以當我們去使用這個類做事情時發現包空指針錯誤,這是因為我們這個類有可能已經初始化完成,但是引用的其他類不一定初始化完成,所以發生了空指針錯誤,解決方案如下: 

1、寫一個類繼承spring的ApplicationListener監聽,並監控ContextRefreshedEvent事件(容易初始化完成事件) 

2、定義簡單的bean:<bean id="beanDefineConfigue" class="com.creatar.portal.webservice.BeanDefineConfigue"></bean> 

或者直接使用@Component("BeanDefineConfigue")注解方式 



完整的類如下: 

package com.creatar.portal.webservice; 

import org.springframework.context.ApplicationListener; 
import org.springframework.context.event.ContextRefreshedEvent; 
import org.springframework.stereotype.Component; 

@Component("BeanDefineConfigue") 
public class BeanDefineConfigue implements 
ApplicationListener<ContextRefreshedEvent> {//ContextRefreshedEvent為初始化完畢事件,spring還有很多事件可以利用 

// @Autowired 
// private IRoleDao roleDao; 


/** 
* 當一個ApplicationContext被初始化或刷新觸發 
*/ 
@Override 
public void onApplicationEvent(ContextRefreshedEvent event) { 
// roleDao.getUserList();//spring容器初始化完畢加載用戶列表到內存 
System.out.println("spring容易初始化完畢================================================"); 








或者使用xml配置方式(非注解),簡單配置個bean即可 

<bean id="beanDefineConfigue" class="com.creatar.portal.webservice.BeanDefineConfigue"></bean> 





其他定義方式: 

完整的類如下: 

package com.creatar.portal.webservice; 

import java.util.ArrayList; 
import java.util.List; 

import org.springframework.context.ApplicationEvent; 
import org.springframework.context.ApplicationListener; 
import org.springframework.context.event.ContextRefreshedEvent; 
import org.springframework.stereotype.Component; 

@Component("BeanDefineConfigue2") 
public class BeanDefineConfigue2 implements ApplicationListener<ApplicationEvent> { 

List<String> list = new ArrayList<String>(); 

/** 
* 當一個ApplicationContext被初始化或刷新觸發 
*/ 
@Override 
public void onApplicationEvent(ApplicationEvent event) { 
if (event instanceof ContextRefreshedEvent) { 
System.out.println("spring容易初始化完畢================================================888"); 






spring其他事件: 

spring中已經內置的幾種事件: 

ContextClosedEvent   、ContextRefreshedEvent  、ContextStartedEvent  、ContextStoppedEvent   、RequestHandleEvent 


后續研究: 
applicationontext和使用MVC之后的webApplicationontext會兩次調用上面的方法,如何區分這個兩種容器呢? 

但是這個時候,會存在一個問題,在web 項目中(spring mvc),系統會存在兩個容器,一個是root application context ,另一個就是我們自己的 projectName-servlet context(作為root application context的子容器)。 

這種情況下,就會造成onApplicationEvent方法被執行兩次。為了避免上面提到的問題,我們可以只在root application context初始化完成后調用邏輯代碼,其他的容器的初始化完成,則不做任何處理,修改后代碼 

如下: 

    @Override  
      public void onApplicationEvent(ContextRefreshedEvent event) {  
        if(event.getApplicationContext().getParent() == null){//root application context 沒有parent,他就是老大.  
             //需要執行的邏輯代碼,當spring容器初始化完成后就會執行該方法。  
        }  
      }  


后續發現加上以上判斷還是能執行兩次,不加的話三次,最終研究結果使用以下判斷更加准確:event.getApplicationContext().getDisplayName().equals("Root WebApplicationContext")


免責聲明!

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



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