ApplicationEvent事件機制源碼分析

spring擴展點之三:Spring 的監聽事件 ApplicationListener 和 ApplicationEvent 用法,在spring啓動後作些事情html

服務網關zuul之七:zuul中的動態刷新路由配置java

 《觀察者模式與監聽模式web

 《JDK自帶的觀察者模式spring

JDK自帶的監聽器模式緩存

ApplicationEvent事件機制源碼分析app

 

在一個事件體系中,有如下幾個重要的概念。
一、事件源:事件對象的產生者,任何一個EventObject都有一個來源
二、事件監聽器註冊表:當事件框架或組件收到一個事件後,須要通知全部相關的事件監聽器來進行處理,這個時候就須要有個存儲監聽器的地方,也就是事件監聽器註冊表。事件源與事件監聽器關聯關係的存儲。
三、事件廣播器:事件廣播器在整個事件機制中扮演一箇中介的角色,當事件發佈者發佈一個事件後,就須要經過廣播器來通知全部相關的監聽器對該事件進行處理。
下圖就是事件機制的結構圖

 

Spring中的監聽器模式框架

一、Spring在事件處理機制中使用了監聽器模式,其中的三個主要角色:

  • 事件,ApplicationEvent,該抽象類繼承了EventObject,EventObject是JDK中的類,並建議全部的事件都應該繼承自EventObject。
  • 事件監聽器,ApplicationListener,是一個接口,該接口繼承了EventListener接口。EventListener接口是JDK中的,建議全部的事件監聽器都應該繼承EventListener。監聽器是用於接收事件,並觸發事件的操做,這樣提及來可能有點費解,簡單的說就是,Listener是監聽ApplicationContext.publishEvent,方法的調用,一旦調用publishEvent,就會執行ApplicaitonListener中的方法,下面這個是ApplicationContext的源碼。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

    /**
     * publishEvent觸發該方方法
     * 能夠在該方法中寫各類業務邏輯
     */
    void onApplicationEvent(E event);

}
  • 事件發佈,ApplicationEventPublisher,ApplicationContext繼承了該接口,在ApplicationContext的抽象實現類AbstractApplicationContext中作了實現。下面會詳解。

 二、Spring事件發佈機制

     在Spring中,事件機制大概也是這麼個結構,具體的實現採用觀察者模式。下面咱們來看看Spring的事件機制設計類圖

三、spring中的事件(異步)機制流程

一、ApplicationEventPublisher是Spring的事件發佈接口,事件源經過該接口的pulishEvent方法發佈事件。
二、ApplicationEventMulticaster就是Spring事件機制中的事件廣播器,它默認提供一個SimpleApplicationEventMulticaster實現,若是用戶沒有自定義廣播器,則使用默認的。它經過父類AbstractApplicationEventMulticaster的getApplicationListeners方法從事件註冊表(事件-監聽器關係保存)中獲取事件監聽器,而且經過invokeListener方法執行監聽器的具體邏輯。
三、ApplicationListener就是Spring的事件監聽器接口,全部的監聽器都實現該接口,本圖中列出了典型的幾個子類。其中RestartApplicationListnener在SpringBoot的啓動框架中就有使用。
四、在Spring中一般是ApplicationContext自己擔任監聽器註冊表的角色,在其子類AbstractApplicationContext中就聚合了事件廣播器ApplicationEventMulticaster和事件監聽器ApplicationListnener,而且提供註冊監聽器的addApplicationListnener方法。
 
     經過上圖就能較清晰的知道當一個事件源產生事件時,它經過事件發佈器ApplicationEventPublisher發佈事件,而後事件廣播器ApplicationEventMulticaster會去事件註冊表ApplicationContext中找到事件監聽器ApplicationListnener,而且逐個執行監聽器的onApplicationEvent方法,從而完成事件監聽器的邏輯。
 
2、Spring中事件有關的源碼

 2.一、Spring事件源

spring-context-4.3.14.RELEASE-sources.jar中的 ApplicationEvent.java
public abstract class ApplicationEvent extends EventObject {

    /** use serialVersionUID from Spring 1.2 for interoperability */
    private static final long serialVersionUID = 7099057708183571937L;

    /** System time when the event happened */
    private final long timestamp;


    /**
     * Create a new ApplicationEvent.
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public ApplicationEvent(Object source) {
        super(source);
        this.timestamp = System.currentTimeMillis();
    }


    /**
     * Return the system time in milliseconds when the event happened.
     */
    public final long getTimestamp() {
        return this.timestamp;
    }

}

 2.二、Spring事件監聽器

spring-context-4.3.14.RELEASE-sources.jar中的ApplicationListener.java類類異步

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

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

}

jdk中的EventListener.java類是一個空接口ide

public interface EventListener {
}

 2.三、Spring事件發佈

spring-context-4.3.14.RELEASE-sources.jar中的ApplicationEventPublisher.java類 
public interface ApplicationEventPublisher {

    /**
     * Notify all <strong>matching</strong> listeners registered with this
     * application of an application event. Events may be framework events
     * (such as RequestHandledEvent) or application-specific events.
     * @param event the event to publish
     * @see org.springframework.web.context.support.RequestHandledEvent
     */
    void publishEvent(ApplicationEvent event);

    /**
     * Notify all <strong>matching</strong> listeners registered with this
     * application of an event.
     * <p>If the specified {@code event} is not an {@link ApplicationEvent},
     * it is wrapped in a {@link PayloadApplicationEvent}.
     * @param event the event to publish
     * @since 4.2
     * @see PayloadApplicationEvent
     */
    void publishEvent(Object event);

}

AbstractApplicationContext類中publishEvent方法實現:源碼分析

    protected void publishEvent(Object event, ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        if (logger.isTraceEnabled()) {
            logger.trace("Publishing event in " + getDisplayName() + ": " + event);
        }

        // Decorate event as an ApplicationEvent if necessary
        ApplicationEvent applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent) event;
        }
        else {
            applicationEvent = new PayloadApplicationEvent<Object>(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 {
            //事件委派給ApplicationEventMulticaster來執行            
       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); } } }

ApplicationEventMulticaster的multicastEvent方法的實如今SimpleApplicationEventMulticaster類中:

    @Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //得到監聽器集合,遍歷監聽器,可支持同步和異步的廣播事件
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
                invokeListener(listener, event);
            }
        }
    }

invokeListener()方法:

這就執行了ApplicationListeneronApplicationEvent方法,這裏是事件發生的地方。

 

2.四、Spring如何根據事件找到事件對應的監聽器

在Spring容器初始化的時候,也就是在AbstractApplicationContext.java在refresh()中:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        ......
        try {
            ......
            // Initialize event multicaster for this context.
            //初始化一個事件註冊表
            initApplicationEventMulticaster();
            ......
            // Check for listener beans and register them.
            //註冊事件監聽器
            registerListeners();

            ......
        }
    }
}

也就是在AbstractApplicationContext.java的initApplicationEventMulticaster方法初始化事件註冊表

protected void initApplicationEventMulticaster() {
    //得到beanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //先查找BeanFactory中是否有ApplicationEventMulticaster
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    }
    else {//若是BeanFactory中不存在,就建立一個SimpleApplicationEventMulticaster
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    }
}

在SimpleApplicationEventMulticaster在父類AbstractApplicationEventMulticaster類中有以下屬性:

//註冊表
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
//註冊表的緩存
private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);

private BeanFactory beanFactory;

ListenerRetriever.java是一個內部類,主要做用:助手類,它封裝特定的目標偵聽器集合,容許對預過濾的偵聽器進行高效的檢索。此助手的實例緩存每一個事件類型和源類型。

ListenerRetriever.java的結構以下:

//用來存放監聽事件
public final Set<ApplicationListener> applicationListeners;
//存放監聽事件的類名稱
public final Set<String> applicationListenerBeans;

private final boolean preFiltered;

初始化註冊表以後,就會把事件註冊到註冊表中,AbstractApplicationContext.registerListeners():

protected void registerListeners() {
    //獲取全部的Listener,把事件的bean放到ApplicationEventMulticaster中
    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!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    //把事件的名稱放到ApplicationListenerBean裏去。
    for (String lisName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(lisName);
    }
}

Spring使用反射機制,經過方法getBeansOfType獲取全部繼承了ApplicationListener接口的監聽器,而後把監聽器放到註冊表中,因此咱們能夠在Spring配置文件中配置自定義監聽器,在Spring初始化的時候,會把監聽器自動註冊到註冊表中去

applicationContext.java中的getBeansOfType(Class<T> type)的實如今

    @Override
    @SuppressWarnings("unchecked")
    public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
            throws BeansException {

        boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type));
        Map<String, T> matches = new LinkedHashMap<String, T>();

        for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
            String beanName = entry.getKey();
            Object beanInstance = entry.getValue();
            // Is bean a FactoryBean?
            if (beanInstance instanceof FactoryBean && !isFactoryType) {
                // Match object created by FactoryBean.
                FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
                Class<?> objectType = factory.getObjectType();
                if ((includeNonSingletons || factory.isSingleton()) &&
                        objectType != null && (type == null || type.isAssignableFrom(objectType))) {
                    matches.put(beanName, getBean(beanName, type));
                }
            }
            else {
                if (type == null || type.isInstance(beanInstance)) {
                    // If type to match is FactoryBean, return FactoryBean itself.
                    // Else, return bean instance.
                    if (isFactoryType) {
                        beanName = FACTORY_BEAN_PREFIX + beanName;
                    }
                    matches.put(beanName, (T) beanInstance);
                }
            }
        }
        return matches;
    }

反射的見《instanceof, isinstance,isAssignableFrom的區別》 

ApplicationContext發佈事件能夠參考上面的內容。發佈事件的時候的一個方法,getApplicationListeners:

protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
    //獲取事件類型
    Class<? extends ApplicationEvent> eventType = event.getClass();
    //或去事件源類型
    Class sourceType = event.getSource().getClass();
    ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
    //從緩存中查找ListenerRetriever
    ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
    //緩存中存在,直接返回對應的Listener
    if (retriever != null) {
        return retriever.getApplicationListeners();
    }
    else {//緩存中不存在,就獲取相應的Listener
        retriever = new ListenerRetriever(true);
        LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
        Set<ApplicationListener> listeners;
        Set<String> listenerBeans;
        synchronized (this.defaultRetriever) {
            listeners = new LinkedHashSet<ApplicationListener>(this.defaultRetriever.applicationListeners);
            listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
        }
        //根據事件類型,事件源類型,獲取所須要的監聽事件
        for (ApplicationListener listener : listeners) {
            if (supportsEvent(listener, eventType, sourceType)) {
                retriever.applicationListeners.add(listener);
                allListeners.add(listener);
            }
        }
        if (!listenerBeans.isEmpty()) {
            BeanFactory beanFactory = getBeanFactory();
            for (String listenerBeanName : listenerBeans) {
                ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                    retriever.applicationListenerBeans.add(listenerBeanName);
                    allListeners.add(listener);
                }
            }
        }
        OrderComparator.sort(allListeners);
        this.retrieverCache.put(cacheKey, retriever);
        return allListeners;
    }
}

 根據事件類型,事件源類型獲取所須要的監聽器supportsEvent(listener, eventType, sourceType):

    protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, Class<?> sourceType) {
        GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
                (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
        return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
    }

這裏沒有進行實際的處理,實際處理在smartListener.supportsEventType(eventType)和smartListener.supportsSourceType(sourceType)方法中。

smartListener.supportsEventType(eventType):

public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
    if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
        Class targetClass = AopUtils.getTargetClass(this.delegate);
        if (targetClass != this.delegate.getClass()) {
            typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
        }
    }
    return (typeArg == null || typeArg.isAssignableFrom(eventType));
}

 該方法主要的邏輯就是根據事件類型判斷是否和監聽器參數泛型的類型是否一致。

smartListener.supportsSourceType(sourceType)方法的實現爲:

public boolean supportsSourceType(Class<?> sourceType) {
    return true;
}

定義本身的監聽器要明確指定參數泛型,代表該監聽器支持的事件,若是不指明具體的泛型,則沒有監聽器監聽事件。

相關文章
相關標籤/搜索