1. 程式人生 > >Spring ApplicationContext(八)事件監聽機制

Spring ApplicationContext(八)事件監聽機制

一個 ace end oid 其它 get throws 規範 bstr

Spring ApplicationContext(八)事件監聽機制

本節則重點關註的是 Spring 的事件監聽機制,主要是第 8 步:多播器註冊;第 10 步:事件註冊。

public void refresh() throws BeansException, IllegalStateException {
    // 8. 註冊多播器,事件監聽器的管理者
    initApplicationEventMulticaster();
    // 9. 專門留給子類初始化其它 bean 用,這是一個空的方法
    onRefresh();
    // 10. 註冊監聽器
    registerListeners();
}

事件定義如下,實現了 JDK 的規範 EventListener

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    // 監聽 event 事件
    void onApplicationEvent(E event);
}

一、ApplicationListener 實戰

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

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("接收的事件:" + event);
    }
}

運行後結果如下:

接收的事件:org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.support.ClassPathXmlApplicationContext@16eabae: startup date [Sun Jul 29 12:41:42 CST 2018]; root of context hierarchy]

二、ApplicationEventMulticaster 多播器的初始化

ApplicationContext 中 refresh() 第 8 步 initApplicationEventMulticaster() 進行多播器的初始化工作

源代碼【AbstractApplicationContext】

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    }
    else {
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    }
}

三、ApplicationListener 註冊

ApplicationContext 中 refresh() 第 10 步 registerListeners() 進行事件監聽者的註冊工作。

源代碼【AbstractApplicationContext】

protected void registerListeners() {
    // 1. 註冊靜態指定的偵聽器
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 2. 註冊 ApplicationListener
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 3. Publish early application events
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

四、ApplicationEvent 事件發布

源代碼【AbstractApplicationContext】

public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
}

public void publishEvent(Object event) {
    publishEvent(event, null);
}

protected void publishEvent(Object event, ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");
   
    // 1. 如果 event 不是 ApplicationEvent,則需要進行封裝成 PayloadApplicationEvent
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<Object>(this, event);
        if (eventType == null) {
            eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass());
        }
    }

    // 2. 發布事件 event,如果多播器懶加載,還沒有初始化則將該事件先放到 earlyApplicationEvents 容器中
    //    等待多播器創建好了再發布事件 ???
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    // 3. 父容器中也需要發布該事件 event
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

每天用心記錄一點點。內容也許不重要,但習慣很重要!

Spring ApplicationContext(八)事件監聽機制