Skip to content

Latest commit

 

History

History
132 lines (98 loc) · 5.03 KB

chapter12.md

File metadata and controls

132 lines (98 loc) · 5.03 KB

SpringMvc事件发布处理流程

首先我们从熟悉的DispatcherServlet说起

熟悉springmvc的人都知道(不熟悉的,可以参考,DispatcherServlet中的onRefresh是通过事件回调执行的。那我们就看一下这个事件回调流程。

FrameworkServlet

根据onRefresh方法的执行回调是ContextRefreshListener监听的ContextRefreshedEvent事件触发的onApplicationEvent方法。而ContextRefreshListener在FrameworkServlet中的configureAndRefreshWebApplicationContext中加载,如下

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {

    wac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));
}

添加方法具体的实现在AbstractApplicationContext

@Override
public void addApplicationListener(ApplicationListener<?> listener) {
        this.applicationListeners.add(listener);
}

由此可以看到事件交给了AbstractApplicationContext处理。那进一步看下是如何处理listener。

AbstractApplicationContext

提到AbstractApplicaitonContext,自然而然的都不想到它最重要的方法refresh方法了,这个方法完成了很多初始化和回调等,是必执行的方法。 由上面的FrameworkServlet的引入,可以看到listener中是有我们的contextRefreshListener的,再查询发现使用listener的地方只有registerListeners

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

getApplicationEventMulticaster返回的是一个ApplicationEventMulticaster对象,而添加方法的实现在,AbstractApplicationEventMulticaster中实现

@Override
public void addApplicationListener(ApplicationListener<?> listener) {
    synchronized (this.retrievalMutex) {
        this.defaultRetriever.applicationListeners.add(listener);
        this.retrieverCache.clear();
    }
}

添加到了ListenerRetriever中的applicationListenersset集合中。

由于AbstractApplicationContext中只有registerListeners对listener进行了添加处理,所以后续的listener处理交给了ApplicationEventMulticaster

ApplicationEventMulticaster

ContextRefreshedEvent事件的触发是在AbstractApplicationContext中的finishRefresh方法中

protected void finishRefresh() {

    // Publish the final event.

    publishEvent(new ContextRefreshedEvent(this));

}

multicastEvent方法的实现是在SimpleApplicationEventMulticaster

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

下面我从getApplicationListeners方法中,看是否能找到一开始添加的listener对象。

protected Collection<ApplicationListener<?>> getApplicationListeners(
        ApplicationEvent event, ResolvableType eventType) {

      Collection<ApplicationListener<?>> listeners =
                            retrieveApplicationListeners(eventType, sourceType, retriever);
    return listeners;
}

retrieveApplicationListeners中的代码如下

	private Collection<ApplicationListener<?>> retrieveApplicationListeners(
			ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {

		LinkedList<ApplicationListener<?>> allListeners = new LinkedList<>();
		Set<ApplicationListener<?>> listeners;
		Set<String> listenerBeans;
		synchronized (this.retrievalMutex) {
			listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
			listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
		}
        for (ApplicationListener<?> listener : listeners) {
                if (supportsEvent(listener, eventType, sourceType)) {
                    if (retriever != null) {
                        retriever.applicationListeners.add(listener);
                    }
                    allListeners.add(listener);
                }
            }
		return allListeners;
	}

defaultRetriever就是我们一开始添加的ListenerRetriever对象,也就和上述的代码关联了起来。

总结:

首先我们要创建一个事件,把事件放入监听器中,然后把监听器交给Spring,等待Spring初始化完成后,触发我们的自定义事件,执行监听器中的方法。

基于注解的使用示例