Spring事件監聽機制原始碼解析

bei_er發表於2022-03-27

Spring事件監聽器使用

1.Spring事件監聽體系包括三個元件:事件、事件監聽器,事件廣播器。

事件:定義事件型別和事件源,需要繼承ApplicationEvent。

package com.ybe.eventLisitener;
import org.springframework.context.ApplicationEvent;

public class OrderEvent extends ApplicationEvent {
    private String name;
    public OrderEvent(Object source,String name) {
        super(source);
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

事件監聽器:用來監聽某一類的事件,並且執行具體業務邏輯,需要實現ApplicationListener 介面或者需要用@ListenerEvent(T)註解。好比觀察者模式中的觀察者。

package com.ybe.eventLisitener;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class OrderEventListener implements ApplicationListener<OrderEvent> {
    @Override
    public void onApplicationEvent(OrderEvent event) {
        if(event.getName().equals("下訂單")){
            System.out.println("下單已完成...");
        }
    }
}

package com.ybe.eventLisitener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class OrderEventListenerByAnnotation  {

    @EventListener(OrderEvent.class)
    public void onApplicationEvent(OrderEvent event) {
        if(event.getName().equals("下訂單")){
            System.out.println("下單已完成...");
        }
    }
}

事件多播器:負責廣播通知所有監聽器,所有的事件監聽器都註冊在了事件多播器中。好比觀察者模式中的被觀察者。Spring容器預設生成的是同步事件多播器。可以自定義事件多播器,定義為非同步方式。

import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.Scanner;

@Configuration
@ComponentScan(value = "com.ybe")
public class Config {
    @Bean
    public ApplicationEventMulticaster applicationEventMulticaster(){
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
        eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return eventMulticaster;
    }
}

Spring事件原始碼分析

1.建立多播器

建立 AnnotationConfigApplicationContext 的過程中,會執行refresh()中的initApplicationEventMulticaster()方法。該方法先獲取bean工廠,然後判斷工廠是否包含了beanName 為 applicationEventMulticaster的bean。如果包含了,則獲取該bean,賦值給applicationEventMulticaster 屬性。如果沒有,則建立一個 SimpleApplicationEventMulticaster 物件,並且賦值給 applicationEventMulticaster 。實現了原始碼如下:

/**
	 * Initialize the ApplicationEventMulticaster.
	 * Uses SimpleApplicationEventMulticaster if none defined in the context.
	 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
	 */
protected void initApplicationEventMulticaster() {
		// 獲取當前bean工廠,一般是DefaultListableBeanFactory
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		// 判斷容器中是否存在bdName為applicationEventMulticaster的bd,
         //也就是說自定義的事件監聽多路廣播器,必須實現  ApplicationEventMulticaster介面
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			// 如果有,則從bean工廠得到這個bean物件
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			// 如果沒有,則預設採用SimpleApplicationEventMulticaster
			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() + "]");
			}
		}
	}

2.註冊監聽器

監聽器的註冊有兩種,通過實現 ApplicationListener介面或者新增@EventListener註解。

一.通過介面方式註冊。實現介面 ApplicationListener

註冊的邏輯實現在refresh()中的registerListeners()方法裡面。第一步,先獲取當前ApplicationContext中已經新增的 applicationListeners(SpringMVC原始碼中有用到),遍歷新增到多播器中。第二步,獲取實現了ApplicationListener介面的listenerBeanNames集合,新增至多播器中。第三步,判斷是否有早期事件,如果有則發起廣播。

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!
      // 從容器中獲取所有實現了ApplicationListener介面的bd的bdName
      // 放入ApplicationListenerBeans集合中
      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 (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
         for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
         }
      }
   }

思考一下,上面的程式碼中第二步為啥新增的是listenerBeanName?

如果監聽器是懶載入的話(即有@Lazy 註解)。那麼在這個時候建立監聽器顯然是不對的,這個時候不能建立監聽器。所以新增監聽器到多播器的具體邏輯放在初始化具體的監聽器之後。通過 BeanPostProcessor 的介面實現。具體的實現類是 ApplicationListenerDetector 。這個類是在 refreah()中prepareBeanFactory()方法中新增的。程式碼如下:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		if (!shouldIgnoreSpel) {
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
    	// 新增 監聽器後置處理器,在初始化具體的實現了 ApplicationListener 介面的Bean之後,進行呼叫。呼叫的是
    	// postProcessAfterInitialization()方法。
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
		if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
			beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
		}
	}
二、通過註解的方式註冊。@EventListener(T)。

在建立 AnnotationConfigApplicationContext 的構造方法中,會執行org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) 方法。這個方法中會新增兩個 beanDefs, 程式碼如下:

if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}

if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}

EventListenerMethodProcessor:事件監聽器的BeanFactory後置處理器,在前期會建立 DefaultEventListenerFactory ,後期在建立好Bean之後,根據 EventListener 屬性,呼叫DefaultEventListenerFactory建立具體的 ApplicationListenerMethodAdapter 。

DefaultEventListenerFactory:監聽器的建立工廠,用來建立 ApplicationListenerMethodAdapter 。

EventListenerMethodProcessor 的類繼承圖如下:

在refreash的invokeBeanFactoryPostProcessors()中會呼叫 org.springframework.context.event.EventListenerMethodProcessor#postProcessBeanFactory方法,獲取EventListenerFactory 型別的 Bean。程式碼如下:

@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.beanFactory = beanFactory;
		// 獲取或建立 EventListenerFactory 型別的 Bean
		Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
		List<EventListenerFactory> factories = new ArrayList<>(beans.values());
		AnnotationAwareOrderComparator.sort(factories);
		this.eventListenerFactories = factories;
	}

在 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons 方法中,建立完所有的單例Bean 之後,會遍歷所有Bean是否實現了 SmartInitializingSingleton 介面。如果實現介面會執行該 Bean 的 afterSingletonsInstantiated() 方法。程式碼如下:

public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		// 將所有BeanDefinition的名字建立一個集合
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 觸發所有非延遲載入單例bean的初始化,遍歷集合的物件
		for (String beanName : beanNames) {
			// 合併父類BeanDefinition
 			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 條件判斷,抽象,單例,非懶載入
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 判斷是否實現了FactoryBean介面
				if (isFactoryBean(beanName)) {
					// 根據&+beanName來獲取具體的物件
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					// 進行型別轉換
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						// 判斷這個FactoryBean是否希望立即初始化
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						//  如果希望急切的初始化,則通過beanName獲取bean例項
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					// 如果beanName對應的bean不是FactoryBean,只是普通的bean,通過beanName獲取bean例項
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// 遍歷beanNames,觸發所有SmartInitializingSingleton的後初始化回撥
		for (String beanName : beanNames) {
			// 獲取beanName對應的bean例項
			Object singletonInstance = getSingleton(beanName);
			// 判斷singletonInstance是否實現了SmartInitializingSingleton介面
			if (singletonInstance instanceof SmartInitializingSingleton) {
				// 型別轉換
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				// 觸發SmartInitializingSingleton實現類的afterSingletonsInstantiated方法
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated 中會呼叫私有方法 processBean()進行 ApplicationEventAdatper 的建立。程式碼如下:

	/**
	 * 該方法拿到某個bean的名稱和它的目標類,再這個範圍上檢測@EventListener註解方法,生成和註冊 ApplicationListenerMethodAdapter 例項
	 * @param beanName
	 * @param targetType
	 */
	private void processBean(final String beanName, final Class<?> targetType) {
		if (!this.nonAnnotatedClasses.contains(targetType) &&
				AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
				!isSpringContainerClass(targetType)) {

			Map<Method, EventListener> annotatedMethods = null;
			try {
				// 檢測當前類targetType上使用了註解@EventListener的方法
				annotatedMethods = MethodIntrospector.selectMethods(targetType,
						(MethodIntrospector.MetadataLookup<EventListener>) method ->
								AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
			}
			catch (Throwable ex) {
				// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
				if (logger.isDebugEnabled()) {
					logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
				}
			}

			if (CollectionUtils.isEmpty(annotatedMethods)) {
				// 如果當前類targetType中沒有任何使用了註解@EventListener的方法,則將該類儲存到快取nonAnnotatedClasses,從而
				// 避免當前處理方法重入該類,避免二次處理
				this.nonAnnotatedClasses.add(targetType);
				if (logger.isTraceEnabled()) {
					logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
				}
			}
			else {
				// Non-empty set of methods
				// 如果當前類targetType中有些方法使用了註解@EventListener,那麼根據方法上的資訊對應的建立和註冊ApplicationListener例項
				ConfigurableApplicationContext context = this.applicationContext;
				Assert.state(context != null, "No ApplicationContext set");
				// 此處使用了this.eventListenerFactories,這些EventListenerFactory是在該類postProcessBeanFactory方法呼叫時被記錄的
				List<EventListenerFactory> factories = this.eventListenerFactories;
				Assert.state(factories != null, "EventListenerFactory List not initialized");
				for (Method method : annotatedMethods.keySet()) {
					for (EventListenerFactory factory : factories) {
						if (factory.supportsMethod(method)) {
							Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
							// 如果當前EventListenerFactory支援處理該@EventListener註解的方法,則使用它建立 ApplicationListenerMethodAdapter
							ApplicationListener<?> applicationListener =
									factory.createApplicationListener(beanName, targetType, methodToUse);
							if (applicationListener instanceof ApplicationListenerMethodAdapter) {
								((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
							}
							// 將建立的ApplicationListener加入到容器中
							context.addApplicationListener(applicationListener);
							break;
						}
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
							beanName + "': " + annotatedMethods);
				}
			}
		}
	}

3.多播器廣播事件

可以通過呼叫 org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType) 方法進行事件的呼叫。程式碼如下:

/**
	 * 將給定事件釋出到所有監聽器
	 */
	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		// 如果event為null,丟擲異常
		Assert.notNull(event, "Event must not be null");

		// Decorate event as an ApplicationEvent if necessary
		// 裝飾事件作為一個應用事件,如果有必要
		ApplicationEvent applicationEvent;
		// 如果event是ApplicationEvent的例項
		if (event instanceof ApplicationEvent) {
			// 將event強轉為ApplicationEvent物件
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			// PayloadApplicationEvent:攜帶任意有效負載的ApplicationEvent。
			// 建立一個新的PayloadApplicationEvent
			applicationEvent = new PayloadApplicationEvent<>(this, event);
			// 如果eventType為 null
			if (eventType == null) {
				// 將applicationEvent轉換為PayloadApplicationEvent 象,引用其ResolvableType物件
				eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		// 如果可能的話,現在就進行組播——或者在組播初始化後延遲
		// earlyApplicationEvents:在多播程式設定之前釋出的ApplicationEvent
		// 如果earlyApplicationEvents不為 null,這種情況只在上下文的多播器還沒有初始化的情況下才會成立,會將applicationEvent
		// 新增到earlyApplicationEvents儲存起來,待多博器初始化後才繼續進行多播到適當的監聽器
		if (this.earlyApplicationEvents != null) {
			//將applicationEvent新增到 earlyApplicationEvents
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
			// 多播applicationEvent到適當的監聽器
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		// 通過父上下文釋出事件
		// 如果parent不為null
		if (this.parent != null) {
			// 如果parent是AbstractApplicationContext的例項
			if (this.parent instanceof AbstractApplicationContext) {
				// 將event多播到所有適合的監聽器。如果event不是ApplicationEvent例項,會將其封裝成PayloadApplicationEvent物件再進行多播
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				// 通知與event事件應用程式註冊的所有匹配的監聽器
				this.parent.publishEvent(event);
			}
		}
	}

SimpleApplicationEventMulticaster 中的 multicasEvent,invokeListener,doInvokeListener 三個方法程式碼如下:

/**
	 * 將給定事件釋出到所有監聽器
	 */
	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		// 如果event為null,丟擲異常
		Assert.notNull(event, "Event must not be null");

		// Decorate event as an ApplicationEvent if necessary
		// 裝飾事件作為一個應用事件,如果有必要
		ApplicationEvent applicationEvent;
		// 如果event是ApplicationEvent的例項
		if (event instanceof ApplicationEvent) {
			// 將event強轉為ApplicationEvent物件
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			// PayloadApplicationEvent:攜帶任意有效負載的ApplicationEvent。
			// 建立一個新的PayloadApplicationEvent
			applicationEvent = new PayloadApplicationEvent<>(this, event);
			// 如果eventType為 null
			if (eventType == null) {
				// 將applicationEvent轉換為PayloadApplicationEvent 象,引用其ResolvableType物件
				eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		// 如果可能的話,現在就進行組播——或者在組播初始化後延遲
		// earlyApplicationEvents:在多播程式設定之前釋出的ApplicationEvent
		// 如果earlyApplicationEvents不為 null,這種情況只在上下文的多播器還沒有初始化的情況下才會成立,會將applicationEvent
		// 新增到earlyApplicationEvents儲存起來,待多博器初始化後才繼續進行多播到適當的監聽器
		if (this.earlyApplicationEvents != null) {
			//將applicationEvent新增到 earlyApplicationEvents
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
			// 多播applicationEvent到適當的監聽器
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		// 通過父上下文釋出事件
		// 如果parent不為null
		if (this.parent != null) {
			// 如果parent是AbstractApplicationContext的例項
			if (this.parent instanceof AbstractApplicationContext) {
				// 將event多播到所有適合的監聽器。如果event不是ApplicationEvent例項,會將其封裝成PayloadApplicationEvent物件再進行多播
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				// 通知與event事件應用程式註冊的所有匹配的監聽器
				this.parent.publishEvent(event);
			}
		}
	}
	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		// 獲取此多播器的當前錯誤處理程式
		ErrorHandler errorHandler = getErrorHandler();
		// 如果errorHandler不為null
		if (errorHandler != null) {
			try {
				// 回撥listener的onApplicationEvent方法,傳入event
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				// 交給errorHandler接收處理err
				errorHandler.handleError(err);
			}
		}
		else {
			// 回撥listener的onApplicationEvent方法,傳入event
			doInvokeListener(listener, event);
		}
	}
	/**
	 * 回撥listener的onApplicationEvent方法,傳入 event
	 * @param listener
	 * @param event
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			//回撥listener的onApplicationEvent方法,傳入	        			event:contextrefreshListener:onapplicaitonEvent:FrameworkServlet.this.onApplicationEvent()
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			//獲取異常資訊
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				//丟擲異常
				throw ex;
			}
		}
	}

SpringMVC中事件使用

SpringMVC中就是通過Spring的事件機制進行九大元件的初始化。

1.ContextRefreshListener監聽器的定義

監聽器定義在FrameworkServlet類中,作為內部類。程式碼如下:

	private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

		@Override
		public void onApplicationEvent(ContextRefreshedEvent event) {
			FrameworkServlet.this.onApplicationEvent(event);
		}
	}

監聽器的新增在org.springframework.web.servlet.FrameworkServlet#configureAndRefreshWebApplicationContext 中進行。通過SourceFilteringListener進行包裝。新增程式碼如下:

	// 新增監聽器sourceFilteringListener到wac中,實際監聽的是ContextRefreshListener所監聽的事件,監聽ContextRefreshedEvent事件,
		// 當接收到訊息之後會呼叫onApplicationEvent方法,呼叫onRefresh方法,並將refreshEventReceived標誌設定為true,表示已經refresh過
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

2.多播器新增已經定義的ContextRefreshListener事件監聽器

在refresh中的registerListeners方法進行新增,程式碼如下:

		// Register statically specified listeners first.
		// 遍歷應用程式中存在的監聽器集合,並將對應的監聽器新增到監聽器的多路廣播器中
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

3.ContextRefreshListener事件監聽器的觸發

在refresh中的finishRefresh()方法中,會呼叫publishEvnet(new ContextRefreshedEvent(this))釋出事件。進行多播器廣播,程式碼如下

// 多播applicationEvent到適當的監聽器
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

最終會調到FrameworkServlet.this.onApplicationEvent(event)。

	public void onApplicationEvent(ContextRefreshedEvent event) {
		// 標記 refreshEventReceived 為true
		this.refreshEventReceived = true;
		synchronized (this.onRefreshMonitor) {
			// 處理事件中的 ApplicationContext 物件,空實現,子類DispatcherServlet會實現
			onRefresh(event.getApplicationContext());
		}
	}
@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}
protected void initStrategies(ApplicationContext context) {
		// 初始化 MultipartResolver:主要用來處理檔案上傳.如果定義過當前型別的bean物件,那麼直接獲取,如果沒有的話,可以為null
		initMultipartResolver(context);
		// 初始化 LocaleResolver:主要用來處理國際化配置,基於URL引數的配置(AcceptHeaderLocaleResolver),基於session的配置(SessionLocaleResolver),基於cookie的配置(CookieLocaleResolver)
		initLocaleResolver(context);
		// 初始化 ThemeResolver:主要用來設定主題Theme
		initThemeResolver(context);
		// 初始化 HandlerMapping:對映器,用來將對應的request跟controller進行對應
		initHandlerMappings(context);
		// 初始化 HandlerAdapter:處理介面卡,主要包含Http請求處理器介面卡,簡單控制器處理器介面卡,註解方法處理器介面卡
		initHandlerAdapters(context);
		// 初始化 HandlerExceptionResolver:基於HandlerExceptionResolver介面的異常處理
		initHandlerExceptionResolvers(context);
		// 初始化 RequestToViewNameTranslator:當controller處理器方法沒有返回一個View物件或邏輯檢視名稱,並且在該方法中沒有直接往response的輸出流裡面寫資料的時候,spring將會採用約定好的方式提供一個邏輯檢視名稱
		initRequestToViewNameTranslator(context);
		// 初始化 ViewResolver: 將ModelAndView選擇合適的檢視進行渲染的處理器
		initViewResolvers(context);
		// 初始化 FlashMapManager: 提供請求儲存屬性,可供其他請求使用
		initFlashMapManager(context);
	}

相關文章