11、Spring之事件監聽

Spring之事件監聽

ApplicationListener

ApplicationListener是Spring事件機制的一部分,與抽象類ApplicationEvent類配合來完成ApplicationContext的事件機制。java

若是容器中存在ApplicationListener的Bean,當ApplicationContext調用publishEvent方法時,對應的Bean會被觸發。這一過程是典型的觀察者模式的實現。spring

源碼app

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

    /**
     * Handle an application event.
     * @param event the event to respond to
     */
    void onApplicationEvent(E event);

}

ContextRefreshedEvent事件的監聽

以Spring的內置事件ContextRefreshedEvent爲例,當ApplicationContext被初始化或刷新時,會觸發ContextRefreshedEvent事件,下面咱們就實現一個ApplicationListener來監聽此事件的發生。ide

@Component // 需對該類進行Bean的實例化
public class LearnListener implements ApplicationListener<ContextRefreshedEvent> {
   @Override
   public void onApplicationEvent(ContextRefreshedEvent event) {
      // 打印容器中出事Bean的數量
      System.out.println("監聽器得到容器中初始化Bean數量:" + event.getApplicationContext().getBeanDefinitionCount());
   }
}

事件發佈

在容器建立完成後,在finishRefresh()方法中發佈了一個事件——ContextRefreshedEventpost

咱們來具體看一下這個事件是如何發佈的this

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");

    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
        }
    }

    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        //獲取事件的派發器
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // Publish event via parent context as well...
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

派發事件:getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);3d

這裏的執行invokeListener主要是來回調listener的接口方法code

以上就是spring中事件發佈的流程。blog

事件派發器

在事件發佈的過程當中,有一步是獲取事件的派發器,那麼事件派發器是在哪裏建立的呢?接口

實際上在容器初始化時,執行了initApplicationEventMulticaster()這個方法,來爲容器初始化事件派發器。

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //先來判斷容器中有沒有applicationEventMulticaster
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        //若是沒有則建立一個派發器
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                         "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
        }
    }
}

APPLICATION_EVENT_MULTICASTER_BEAN_NAME:

public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

監聽器從哪裏來

refresh()方法中執行了registerListeners()來給容器中註冊監聽器

protected void registerListeners() {
    // Register statically specified listeners first.
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    //根據類型獲取全部的監聽器的Bean名稱
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
       //將監聽器加入到派發器當中
       getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // Publish early application events now that we finally have a multicaster...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

@EventListener

除了實現ApplicationListener接口來完成事件監聽之外,@EventListener這個註解也一樣能夠監聽事件的發生

只須要將@EventListener標註在方法上面:

@EventListener(classes = {ApplicationEvent.class})
public void listen(ApplicationEvent applicationEvent){
    System.out.println("監聽到:"+applicationEvent);
}
相關文章
相關標籤/搜索