spring boot 之監聽器ApplicationListener


監聽器
ApplicationListener 就是spring的監聽器,能夠用來監聽事件,典型的觀察者模式。
ApplicationListener和ContextRefreshedEvent一般都是成對出現的
在IOC容器的啟動過程中,當所有的bean都已經處理完成之后,spring ioc容器會有一個發布事件的動作。從AbstractApplicationContext 的源碼中可以看出:

/**
 * Finish the refresh of this context, invoking the LifecycleProcessor's
 * onRefresh() method and publishing the
 * {@link org.springframework.context.event.ContextRefreshedEvent}.
 */
protected void finishRefresh() {
   // Clear context-level resource caches (such as ASM metadata from scanning).
   clearResourceCaches();

   // Initialize lifecycle processor for this context.
   initLifecycleProcessor();

   // Propagate refresh to lifecycle processor first.
   getLifecycleProcessor().onRefresh();

   // Publish the final event.
   publishEvent(new ContextRefreshedEvent(this));

   // Participate in LiveBeansView MBean, if active.
   LiveBeansView.registerApplicationContext(this);
}

這樣,當ioc容器加載處理完相應的bean之后,也給我們提供了一個機會(先有InitializingBean,后有ApplicationListener<ContextRefreshedEvent>),可以去做一些自己想做的事。其實這也就是spring ioc容器給提供的一個擴展的地方。我們可以這樣使用這個擴展機制。
一個最簡單的方式就是,讓我們的bean實現ApplicationListener接口,這樣當發布事件時,spring 的ioc容器就會以容器的實例對象作為事件源類,並從中找到事件的監聽者,此時ApplicationListener接口實例中的onApplicationEvent(E event)方法就會被調用,我們的邏輯代碼就會寫在此處。這樣我們的目的就達到了。但這也帶來一個思考,有人可能會想,這樣的代碼我們也可以通過實現spring 的InitializingBean接口來實現啊,也會被spring 容器去自動調用,但是大家應該想到,如果我們現在想做的事,是必須要等到所有的bean都被處理完成之后再進行,此時InitializingBean接口的實現就不合適了,所以需要深刻理解事件機制的應用場合。
系統會存在兩個容器,一個是root application context ,另一個就是我們自己的 projectName-servlet context(作為root application context的子容器)
這種情況下,就會造成onApplicationEvent方法被執行兩次。為了避免上面提到的問題,我們可以只在root application context初始化完成后調用邏輯代碼,其他的容器的初始化完成,則不做任何處理
簡單示例代碼如下:

package com.example.demo.init;

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

@Component
public class ZkServerInit implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent context) {
        if (null == context.getApplicationContext().getParent()) {
            System.err.println("初始化zkServer...");
            // 初始化邏輯...
            System.err.println("初始化zkServer完成...");
        }
    }
}


免責聲明!

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



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