关于对Spring事件监听机制相关解析

news2024/11/25 16:27:06

1、Spring事件监听器使用

Spring事件监听体系包括三个组件:事件、事件监听器,事件广播器
事件:定义事件类型和事件源,需要继承ApplicationEvent

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)注解。下面分别有两种实现

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("下单已完成...");
        }
    }
}
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;
@Configuration
@ComponentScan(value = "com.ybe")
public class Config {
    @Bean
    public ApplicationEventMulticaster applicationEventMulticaster(){
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
        eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
        // todo
        return eventMulticaster;
    }
}

2、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() + "]");
			}
		}
	}
  1. 注册监听器
    监听器的注册有两种,通过实现 ApplicationListener接口或者添加@EventListener注解。
    一.通过接口方式注册。实现接口 ApplicationListener。
    注册的逻辑实现在refresh()中的registerListeners()方法里面。第一步,先获取当前ApplicationContext中已经添加的 applicationListeners(SpringMVC,springboot的run启动流程源码中有用到),遍历添加到多播器中。第二步,获取实现了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);
				}
			}
		}
	}
  1. 多播器广播事件
    可以通过调用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;
			}
		}
	}

3、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()));
  1. 多播器添加已经定义的ContextRefreshListener事件监听器
    在refresh中的registerListeners方法进行添加,代码如下:
// Register statically specified listeners first.
		// 遍历应用程序中存在的监听器集合,并将对应的监听器添加到监听器的多路广播器中
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}
  1. 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);
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1288649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springcloud智慧工地管理平台源码(工程全生命周期管理)

智慧工地采用全新的工程全生命周期管理理念&#xff0c;以物联网技术为核心&#xff0c;利用传感网络、远程视频监控、物联网、云计算等新型技术&#xff0c;依托移动和固定宽带网络&#xff0c;围绕施工过程管理&#xff0c;建造互联协同、智能生产、科学管理的信息化生态圈&a…

Python源码分享10:使用海龟画图turtle画哆啦A梦

turtle模块是一个Python的标准库之一&#xff0c;它提供了一个基于Turtle graphics的绘图库。Turtle graphics是一种流行的绘图方式&#xff0c;它通过控制一个小海龟在屏幕上移动来绘制图形。 turtle模块可以让您轻松地创建和控制海龟图形&#xff0c;从而帮助您学习Python编…

虚拟网络技术:bond技术

网卡bond也称为网卡捆绑&#xff0c;就是将两个或者更多的物理网卡绑定成一个虚拟网卡。 bond的作用&#xff1a; 1.提高网卡的吞吐量 2.增加网络的高可用&#xff0c;实现负载均衡。 一、bond简介 bond技术即bonding&#xff0c;能将多块物理网卡绑定到一块虚拟网卡上&…

AMEYA360--罗姆与Quanmatic公司利用量子技术优化制造工序并完成验证

全球知名半导体制造商罗姆(总部位于日本京都市)于2023年1月起与 Quanmatic Inc.(总部位于日本东京都新宿区&#xff0c;以下简称“Quanmatic”)展开合作&#xff0c;在半导体制造工序之一的EDS工序中测试并引入量子技术&#xff0c;以优化制造工序中的组合。目前&#xff0c;双…

springMVC实验(五)——数据校验

【知识要点】 数据校验的概念 在软件开发过程中&#xff0c;数据校验是非常重要的环节&#xff0c;用于确保数据的有效性和完整性 。数据校验分为客户端验证和服务端验证&#xff0c;客户端验证是确保人机交互过程中用户操作表单过程中的误操作&#xff0c;由JavaScript代码完…

Geoserver发布2000坐标系遇到的问题总结

在Geoserver上发布2000坐标系的服务时&#xff0c;要想正常发布服务&#xff0c;不仅仅是要涉及2000坐标系&#xff0c;还需要在发布的时候选择对坐标系。具体问题描述如下&#xff1a; 1.问题描述&#xff1a; 在发布好2000坐标系的服务后&#xff0c;在超图的平台加载服务时&…

联合基于信息论的安全和隐蔽通信的框架

这个标题很帅 abstractintroductionsystem modelPROPOSED JOINT OPTIMIZATION OF ITS AND COVERT TRANSMISSION RATE信息论安全 &#xff08;ITS&#xff09; Joint Information-Theoretic Secrecy and Covert Communication in the Presence of an Untrusted User and Warden …

根文件系统中文字符测试

一. 简介 本文在之前制作的根文件系统可以正常运行的基础上进行的&#xff0c;继上一篇文章地址如下&#xff1a; 根文件系统初步测试-CSDN博客 本文测试根文件系统的是否可以支持中文字符。 二. 根文件系统中文字符测试 1. 创建中文文件 打开 ubuntu虚拟机&#xff0c;进…

uniapp-hubildx配置

1.配置浏览器 &#xff08;1&#xff09;运行》运行到浏览器配置》配置web服务器 &#xff08;2&#xff09;选择浏览器安装路径 &#xff08;3&#xff09;浏览器安装路径&#xff1a; &#xff08;3.1&#xff09; 右键点击图标》属性 &#xff08;3.2&#xff09;选择目标&…

计算机组成原理-数据寻址-(相对寻址 基址寻址 变址寻址 )

文章目录 指令寻址vs数据寻址总览偏移寻址基址寻址基址寻址的作用变址寻址变址寻址的作用基址&变址复合寻址相对寻址相对寻址的作用 总结硬件如何实现数的比较 指令寻址vs数据寻址 总览 偏移寻址 变址寄存器&#xff1a;IX 基址寄存器&#xff1a;BR 基址寻址 没有基址…

EM32DX-C4【C#】站15

1外观&#xff1a; J301 直流 24V 电源输入 CAN0 CAN0 总线接口 CAN1 CAN1 总线接口 J201 IO 接线段子 S301-1、S301-2 输出口初始电平拨码设置 S301-3~S301-6 模块 CAN ID 站号拨码开关 S301-7 模块波特率拨码设置 S301-8 终端电阻选择开关 2DI&#xff1a; 公共端是…

HarmonyOS学习--初次下载安装和配置环境

一、Windows下载与安装软件 运行环境要求&#xff1a; 为保证DevEco Studio正常运行&#xff0c;建议电脑配置满足如下要求&#xff1a; 操作系统&#xff1a;Windows10 64位、Windows11 64位内存&#xff1a;8GB及以上硬盘&#xff1a;100GB及以上分辨率&#xff1a;1280*80…

第二证券:服务消费暖意尽显 产业升级促投资稳出口

如果说完结全年增加方针问题不大代表了2023年我国经济的“形”&#xff0c;那么消费、出资、出口这“三驾马车”在驱动增加过程中的结构性亮点则展示了我国经济的“势”。 2023年&#xff0c;服务消费暖意尽显&#xff0c;餐饮、文旅工作展示出的生气勃勃浮光掠影&#xff1b;…

群星璀璨!亚信科技、TM Forum联合举办数字领导力中国峰会,助百行千业打造转型升级双引擎

11月30日&#xff0c;亚信科技携手著名国际组织TM Forum&#xff08;TeleManagement Forum 电信管理论坛&#xff09;联合举办的2023数字领导力中国峰会在京隆重召开&#xff0c;国内外数百位行业领袖、专家学者、企业高管和生态伙伴齐聚一堂。大会由“数字领导力峰会”“IT数字…

为什么C语言用int *a 来声明指针变量,而不是int a声明?

为什么C语言用int *a 来声明指针变量&#xff0c;而不是int &a声明&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「C语言从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c…

第一节:认识微服务

一、微服务技术对比 Dubbo SpringCloudSpringCloudAlibaba注册中心zookeeper、Redis Eureka、ConsulNacos、Eureka服务远程调用Dubbo协议Feign&#xff08;http协议&#xff09;Dubbo、Feign配置中心无SpringCloudGateway、ZuulSpringCloudConfig、Nacos服务网…

React中ref的四种使用方法

个人公众号 公众号文章-React中ref的四种使用方法 个人公众号&#xff0c;求关注公众号~ 求指导&#xff0c;求点赞&#xff0c;求评论。 写在前面的废话 什么时候使用ref的环境就不说了&#xff0c;比如我们要获取一个输入框的value&#xff0c;无法通过state去获取&#x…

固态硬盘速度测试:硬盘实际性能是否符合标准?

在进行固态硬盘速度测试之前我们先来了解一下固态硬盘的读写速度是什么。固态硬盘的读写速度主要分为顺序读写和随机读写&#xff08;4K&#xff09;。 ​顺序读写&#xff1a;指的是硬盘在读写连贯、集中大文件时候的速度。比如在读取、拷贝单个视频文件时&#xff0c;就是硬盘…

Light-Head R-CNN: In Defense of Two-Stage Object Detector(2017.11)

文章目录 Abstract1. Introduction2. Related works3. Our Approach3.1. Light-Head R-CNN3.1.1. R-CNN subnet3.1.2. Thin feature maps for RoI warping 3.2. Light-Head R-CNN for Object Detection Conclusion 原文链接 Abstract 在本文中&#xff0c;我们首先研究了为什么…

如何能够获得想要的科研数据资料呢?

在当今的学术界&#xff0c;科研数据的获取对于研究人员来说至关重要。然而&#xff0c;由于各种原因&#xff0c;如数据难以获取、数据不完整或不准确等&#xff0c;使得许多研究人员面临困难。那么&#xff0c;如何才能够获得的科研数据资料呢&#xff1f; 一、参考文献 根…