Spring事件监听器使用

1.Spring事件监听体系包括三个组件:事件、事件监听器,事件广播器。

事件:定义事件类型和事件源,需要继承ApplicationEvent。

  1. package com.ybe.eventLisitener;
  2. import org.springframework.context.ApplicationEvent;
  3. public class OrderEvent extends ApplicationEvent {
  4. private String name;
  5. public OrderEvent(Object source,String name) {
  6. super(source);
  7. this.name = name;
  8. }
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. }

事件监听器:用来监听某一类的事件,并且执行具体业务逻辑,需要实现ApplicationListener 接口或者需要用@ListenerEvent(T)注解。好比观察者模式中的观察者。

  1. package com.ybe.eventLisitener;
  2. import org.springframework.context.ApplicationListener;
  3. import org.springframework.stereotype.Component;
  4. @Component
  5. public class OrderEventListener implements ApplicationListener<OrderEvent> {
  6. @Override
  7. public void onApplicationEvent(OrderEvent event) {
  8. if(event.getName().equals("下订单")){
  9. System.out.println("下单已完成...");
  10. }
  11. }
  12. }
  1. package com.ybe.eventLisitener;
  2. import org.springframework.context.ApplicationListener;
  3. import org.springframework.context.event.EventListener;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. public class OrderEventListenerByAnnotation {
  7. @EventListener(OrderEvent.class)
  8. public void onApplicationEvent(OrderEvent event) {
  9. if(event.getName().equals("下订单")){
  10. System.out.println("下单已完成...");
  11. }
  12. }
  13. }

事件多播器:负责广播通知所有监听器,所有的事件监听器都注册在了事件多播器中。好比观察者模式中的被观察者。Spring容器默认生成的是同步事件多播器。可以自定义事件多播器,定义为异步方式。

  1. import org.springframework.context.event.ApplicationEventMulticaster;
  2. import org.springframework.context.event.SimpleApplicationEventMulticaster;
  3. import org.springframework.core.task.SimpleAsyncTaskExecutor;
  4. import org.springframework.stereotype.Component;
  5. import java.util.Scanner;
  6. @Configuration
  7. @ComponentScan(value = "com.ybe")
  8. public class Config {
  9. @Bean
  10. public ApplicationEventMulticaster applicationEventMulticaster(){
  11. SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
  12. eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
  13. return eventMulticaster;
  14. }
  15. }

Spring事件源码分析

1.创建多播器

创建 AnnotationConfigApplicationContext 的过程中,会执行refresh()中的initApplicationEventMulticaster()方法。该方法先获取bean工厂,然后判断工厂是否包含了beanName 为 applicationEventMulticaster的bean。如果包含了,则获取该bean,赋值给applicationEventMulticaster 属性。如果没有,则创建一个 SimpleApplicationEventMulticaster 对象,并且赋值给 applicationEventMulticaster 。实现了源码如下:

  1. /**
  2. * Initialize the ApplicationEventMulticaster.
  3. * Uses SimpleApplicationEventMulticaster if none defined in the context.
  4. * @see org.springframework.context.event.SimpleApplicationEventMulticaster
  5. */
  6. protected void initApplicationEventMulticaster() {
  7. // 获取当前bean工厂,一般是DefaultListableBeanFactory
  8. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  9. // 判断容器中是否存在bdName为applicationEventMulticaster的bd,
  10. //也就是说自定义的事件监听多路广播器,必须实现 ApplicationEventMulticaster接口
  11. if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
  12. // 如果有,则从bean工厂得到这个bean对象
  13. this.applicationEventMulticaster =
  14. beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
  15. if (logger.isTraceEnabled()) {
  16. logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
  17. }
  18. }
  19. else {
  20. // 如果没有,则默认采用SimpleApplicationEventMulticaster
  21. this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
  22. beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
  23. if (logger.isTraceEnabled()) {
  24. logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
  25. "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
  26. }
  27. }
  28. }

2.注册监听器

监听器的注册有两种,通过实现 ApplicationListener接口或者添加@EventListener注解。

一.通过接口方式注册。实现接口 ApplicationListener。

注册的逻辑实现在refresh()中的registerListeners()方法里面。第一步,先获取当前ApplicationContext中已经添加的 applicationListeners(SpringMVC源码中有用到),遍历添加到多播器中。第二步,获取实现了ApplicationListener接口的listenerBeanNames集合,添加至多播器中。第三步,判断是否有早期事件,如果有则发起广播。

  1. protected void registerListeners() {
  2. // Register statically specified listeners first.
  3. // 遍历应用程序中存在的监听器集合,并将对应的监听器添加到监听器的多路广播器中
  4. for (ApplicationListener<?> listener : getApplicationListeners()) {
  5. getApplicationEventMulticaster().addApplicationListener(listener);
  6. }
  7. // Do not initialize FactoryBeans here: We need to leave all regular beans
  8. // uninitialized to let post-processors apply to them!
  9. // 从容器中获取所有实现了ApplicationListener接口的bd的bdName
  10. // 放入ApplicationListenerBeans集合中
  11. String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
  12. for (String listenerBeanName : listenerBeanNames) {
  13. getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  14. }
  15. // Publish early application events now that we finally have a multicaster...
  16. // 此处先发布早期的监听器集合
  17. Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
  18. this.earlyApplicationEvents = null;
  19. if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
  20. for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
  21. getApplicationEventMulticaster().multicastEvent(earlyEvent);
  22. }
  23. }
  24. }

思考一下,上面的代码中第二步为啥添加的是listenerBeanName?

如果监听器是懒加载的话(即有@Lazy 注解)。那么在这个时候创建监听器显然是不对的,这个时候不能创建监听器。所以添加监听器到多播器的具体逻辑放在初始化具体的监听器之后。通过 BeanPostProcessor 的接口实现。具体的实现类是 ApplicationListenerDetector 。这个类是在 refreah()中prepareBeanFactory()方法中添加的。代码如下:

  1. protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  2. // Tell the internal bean factory to use the context's class loader etc.
  3. beanFactory.setBeanClassLoader(getClassLoader());
  4. if (!shouldIgnoreSpel) {
  5. beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  6. }
  7. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
  8. // Configure the bean factory with context callbacks.
  9. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  10. beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  11. beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
  12. beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  13. beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  14. beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  15. beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
  16. beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
  17. // BeanFactory interface not registered as resolvable type in a plain factory.
  18. // MessageSource registered (and found for autowiring) as a bean.
  19. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  20. beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  21. beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  22. beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  23. // Register early post-processor for detecting inner beans as ApplicationListeners.
  24. // 添加 监听器后置处理器,在初始化具体的实现了 ApplicationListener 接口的Bean之后,进行调用。调用的是
  25. // postProcessAfterInitialization()方法。
  26. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
  27. // Detect a LoadTimeWeaver and prepare for weaving, if found.
  28. if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
  29. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  30. // Set a temporary ClassLoader for type matching.
  31. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  32. }
  33. // Register default environment beans.
  34. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
  35. beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  36. }
  37. if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
  38. beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
  39. }
  40. if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
  41. beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
  42. }
  43. if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
  44. beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
  45. }
  46. }
二、通过注解的方式注册。@EventListener(T)。

在创建 AnnotationConfigApplicationContext 的构造方法中,会执行org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) 方法。这个方法中会添加两个 beanDefs, 代码如下:

  1. if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
  2. RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
  3. def.setSource(source);
  4. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
  5. }
  6. if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
  7. RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
  8. def.setSource(source);
  9. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
  10. }

EventListenerMethodProcessor:事件监听器的BeanFactory后置处理器,在前期会创建 DefaultEventListenerFactory ,后期在创建好Bean之后,根据 EventListener 属性,调用DefaultEventListenerFactory创建具体的 ApplicationListenerMethodAdapter 。

DefaultEventListenerFactory:监听器的创建工厂,用来创建 ApplicationListenerMethodAdapter 。

EventListenerMethodProcessor 的类继承图如下:

在refreash的invokeBeanFactoryPostProcessors()中会调用 org.springframework.context.event.EventListenerMethodProcessor#postProcessBeanFactory方法,获取EventListenerFactory 类型的 Bean。代码如下:

  1. @Override
  2. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  3. this.beanFactory = beanFactory;
  4. // 获取或创建 EventListenerFactory 类型的 Bean
  5. Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
  6. List<EventListenerFactory> factories = new ArrayList<>(beans.values());
  7. AnnotationAwareOrderComparator.sort(factories);
  8. this.eventListenerFactories = factories;
  9. }

在 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons 方法中,创建完所有的单例Bean 之后,会遍历所有Bean是否实现了 SmartInitializingSingleton 接口。如果实现接口会执行该 Bean 的 afterSingletonsInstantiated() 方法。代码如下:

  1. public void preInstantiateSingletons() throws BeansException {
  2. if (logger.isTraceEnabled()) {
  3. logger.trace("Pre-instantiating singletons in " + this);
  4. }
  5. // Iterate over a copy to allow for init methods which in turn register new bean definitions.
  6. // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
  7. // 将所有BeanDefinition的名字创建一个集合
  8. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
  9. // Trigger initialization of all non-lazy singleton beans...
  10. // 触发所有非延迟加载单例bean的初始化,遍历集合的对象
  11. for (String beanName : beanNames) {
  12. // 合并父类BeanDefinition
  13. RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
  14. // 条件判断,抽象,单例,非懒加载
  15. if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
  16. // 判断是否实现了FactoryBean接口
  17. if (isFactoryBean(beanName)) {
  18. // 根据&+beanName来获取具体的对象
  19. Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
  20. // 进行类型转换
  21. if (bean instanceof FactoryBean) {
  22. FactoryBean<?> factory = (FactoryBean<?>) bean;
  23. // 判断这个FactoryBean是否希望立即初始化
  24. boolean isEagerInit;
  25. if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
  26. isEagerInit = AccessController.doPrivileged(
  27. (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
  28. getAccessControlContext());
  29. }
  30. else {
  31. isEagerInit = (factory instanceof SmartFactoryBean &&
  32. ((SmartFactoryBean<?>) factory).isEagerInit());
  33. }
  34. // 如果希望急切的初始化,则通过beanName获取bean实例
  35. if (isEagerInit) {
  36. getBean(beanName);
  37. }
  38. }
  39. }
  40. else {
  41. // 如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例
  42. getBean(beanName);
  43. }
  44. }
  45. }
  46. // Trigger post-initialization callback for all applicable beans...
  47. // 遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调
  48. for (String beanName : beanNames) {
  49. // 获取beanName对应的bean实例
  50. Object singletonInstance = getSingleton(beanName);
  51. // 判断singletonInstance是否实现了SmartInitializingSingleton接口
  52. if (singletonInstance instanceof SmartInitializingSingleton) {
  53. // 类型转换
  54. SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
  55. // 触发SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
  56. if (System.getSecurityManager() != null) {
  57. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  58. smartSingleton.afterSingletonsInstantiated();
  59. return null;
  60. }, getAccessControlContext());
  61. }
  62. else {
  63. smartSingleton.afterSingletonsInstantiated();
  64. }
  65. }
  66. }
  67. }

org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated 中会调用私有方法 processBean()进行 ApplicationEventAdatper 的创建。代码如下:

  1. /**
  2. * 该方法拿到某个bean的名称和它的目标类,再这个范围上检测@EventListener注解方法,生成和注册 ApplicationListenerMethodAdapter 实例
  3. * @param beanName
  4. * @param targetType
  5. */
  6. private void processBean(final String beanName, final Class<?> targetType) {
  7. if (!this.nonAnnotatedClasses.contains(targetType) &&
  8. AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
  9. !isSpringContainerClass(targetType)) {
  10. Map<Method, EventListener> annotatedMethods = null;
  11. try {
  12. // 检测当前类targetType上使用了注解@EventListener的方法
  13. annotatedMethods = MethodIntrospector.selectMethods(targetType,
  14. (MethodIntrospector.MetadataLookup<EventListener>) method ->
  15. AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
  16. }
  17. catch (Throwable ex) {
  18. // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
  19. if (logger.isDebugEnabled()) {
  20. logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
  21. }
  22. }
  23. if (CollectionUtils.isEmpty(annotatedMethods)) {
  24. // 如果当前类targetType中没有任何使用了注解@EventListener的方法,则将该类保存到缓存nonAnnotatedClasses,从而
  25. // 避免当前处理方法重入该类,避免二次处理
  26. this.nonAnnotatedClasses.add(targetType);
  27. if (logger.isTraceEnabled()) {
  28. logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
  29. }
  30. }
  31. else {
  32. // Non-empty set of methods
  33. // 如果当前类targetType中有些方法使用了注解@EventListener,那么根据方法上的信息对应的创建和注册ApplicationListener实例
  34. ConfigurableApplicationContext context = this.applicationContext;
  35. Assert.state(context != null, "No ApplicationContext set");
  36. // 此处使用了this.eventListenerFactories,这些EventListenerFactory是在该类postProcessBeanFactory方法调用时被记录的
  37. List<EventListenerFactory> factories = this.eventListenerFactories;
  38. Assert.state(factories != null, "EventListenerFactory List not initialized");
  39. for (Method method : annotatedMethods.keySet()) {
  40. for (EventListenerFactory factory : factories) {
  41. if (factory.supportsMethod(method)) {
  42. Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
  43. // 如果当前EventListenerFactory支持处理该@EventListener注解的方法,则使用它创建 ApplicationListenerMethodAdapter
  44. ApplicationListener<?> applicationListener =
  45. factory.createApplicationListener(beanName, targetType, methodToUse);
  46. if (applicationListener instanceof ApplicationListenerMethodAdapter) {
  47. ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
  48. }
  49. // 将创建的ApplicationListener加入到容器中
  50. context.addApplicationListener(applicationListener);
  51. break;
  52. }
  53. }
  54. }
  55. if (logger.isDebugEnabled()) {
  56. logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
  57. beanName + "': " + annotatedMethods);
  58. }
  59. }
  60. }
  61. }

3.多播器广播事件

可以通过调用 org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType) 方法进行事件的调用。代码如下:

  1. /**
  2. * 将给定事件发布到所有监听器
  3. */
  4. protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
  5. // 如果event为null,抛出异常
  6. Assert.notNull(event, "Event must not be null");
  7. // Decorate event as an ApplicationEvent if necessary
  8. // 装饰事件作为一个应用事件,如果有必要
  9. ApplicationEvent applicationEvent;
  10. // 如果event是ApplicationEvent的实例
  11. if (event instanceof ApplicationEvent) {
  12. // 将event强转为ApplicationEvent对象
  13. applicationEvent = (ApplicationEvent) event;
  14. }
  15. else {
  16. // PayloadApplicationEvent:携带任意有效负载的ApplicationEvent。
  17. // 创建一个新的PayloadApplicationEvent
  18. applicationEvent = new PayloadApplicationEvent<>(this, event);
  19. // 如果eventType为 null
  20. if (eventType == null) {
  21. // 将applicationEvent转换为PayloadApplicationEvent 象,引用其ResolvableType对象
  22. eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
  23. }
  24. }
  25. // Multicast right now if possible - or lazily once the multicaster is initialized
  26. // 如果可能的话,现在就进行组播——或者在组播初始化后延迟
  27. // earlyApplicationEvents:在多播程序设置之前发布的ApplicationEvent
  28. // 如果earlyApplicationEvents不为 null,这种情况只在上下文的多播器还没有初始化的情况下才会成立,会将applicationEvent
  29. // 添加到earlyApplicationEvents保存起来,待多博器初始化后才继续进行多播到适当的监听器
  30. if (this.earlyApplicationEvents != null) {
  31. //将applicationEvent添加到 earlyApplicationEvents
  32. this.earlyApplicationEvents.add(applicationEvent);
  33. }
  34. else {
  35. // 多播applicationEvent到适当的监听器
  36. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
  37. }
  38. // Publish event via parent context as well...
  39. // 通过父上下文发布事件
  40. // 如果parent不为null
  41. if (this.parent != null) {
  42. // 如果parent是AbstractApplicationContext的实例
  43. if (this.parent instanceof AbstractApplicationContext) {
  44. // 将event多播到所有适合的监听器。如果event不是ApplicationEvent实例,会将其封装成PayloadApplicationEvent对象再进行多播
  45. ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
  46. }
  47. else {
  48. // 通知与event事件应用程序注册的所有匹配的监听器
  49. this.parent.publishEvent(event);
  50. }
  51. }
  52. }

SimpleApplicationEventMulticaster 中的 multicasEvent,invokeListener,doInvokeListener 三个方法代码如下:

  1. /**
  2. * 将给定事件发布到所有监听器
  3. */
  4. protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
  5. // 如果event为null,抛出异常
  6. Assert.notNull(event, "Event must not be null");
  7. // Decorate event as an ApplicationEvent if necessary
  8. // 装饰事件作为一个应用事件,如果有必要
  9. ApplicationEvent applicationEvent;
  10. // 如果event是ApplicationEvent的实例
  11. if (event instanceof ApplicationEvent) {
  12. // 将event强转为ApplicationEvent对象
  13. applicationEvent = (ApplicationEvent) event;
  14. }
  15. else {
  16. // PayloadApplicationEvent:携带任意有效负载的ApplicationEvent。
  17. // 创建一个新的PayloadApplicationEvent
  18. applicationEvent = new PayloadApplicationEvent<>(this, event);
  19. // 如果eventType为 null
  20. if (eventType == null) {
  21. // 将applicationEvent转换为PayloadApplicationEvent 象,引用其ResolvableType对象
  22. eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
  23. }
  24. }
  25. // Multicast right now if possible - or lazily once the multicaster is initialized
  26. // 如果可能的话,现在就进行组播——或者在组播初始化后延迟
  27. // earlyApplicationEvents:在多播程序设置之前发布的ApplicationEvent
  28. // 如果earlyApplicationEvents不为 null,这种情况只在上下文的多播器还没有初始化的情况下才会成立,会将applicationEvent
  29. // 添加到earlyApplicationEvents保存起来,待多博器初始化后才继续进行多播到适当的监听器
  30. if (this.earlyApplicationEvents != null) {
  31. //将applicationEvent添加到 earlyApplicationEvents
  32. this.earlyApplicationEvents.add(applicationEvent);
  33. }
  34. else {
  35. // 多播applicationEvent到适当的监听器
  36. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
  37. }
  38. // Publish event via parent context as well...
  39. // 通过父上下文发布事件
  40. // 如果parent不为null
  41. if (this.parent != null) {
  42. // 如果parent是AbstractApplicationContext的实例
  43. if (this.parent instanceof AbstractApplicationContext) {
  44. // 将event多播到所有适合的监听器。如果event不是ApplicationEvent实例,会将其封装成PayloadApplicationEvent对象再进行多播
  45. ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
  46. }
  47. else {
  48. // 通知与event事件应用程序注册的所有匹配的监听器
  49. this.parent.publishEvent(event);
  50. }
  51. }
  52. }
  1. protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
  2. // 获取此多播器的当前错误处理程序
  3. ErrorHandler errorHandler = getErrorHandler();
  4. // 如果errorHandler不为null
  5. if (errorHandler != null) {
  6. try {
  7. // 回调listener的onApplicationEvent方法,传入event
  8. doInvokeListener(listener, event);
  9. }
  10. catch (Throwable err) {
  11. // 交给errorHandler接收处理err
  12. errorHandler.handleError(err);
  13. }
  14. }
  15. else {
  16. // 回调listener的onApplicationEvent方法,传入event
  17. doInvokeListener(listener, event);
  18. }
  19. }
  1. /**
  2. * 回调listener的onApplicationEvent方法,传入 event
  3. * @param listener
  4. * @param event
  5. */
  6. @SuppressWarnings({"rawtypes", "unchecked"})
  7. private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
  8. try {
  9. //回调listener的onApplicationEvent方法,传入 event:contextrefreshListener:onapplicaitonEvent:FrameworkServlet.this.onApplicationEvent()
  10. listener.onApplicationEvent(event);
  11. }
  12. catch (ClassCastException ex) {
  13. //获取异常信息
  14. String msg = ex.getMessage();
  15. if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
  16. // Possibly a lambda-defined listener which we could not resolve the generic event type for
  17. // -> let's suppress the exception and just log a debug message.
  18. Log logger = LogFactory.getLog(getClass());
  19. if (logger.isTraceEnabled()) {
  20. logger.trace("Non-matching event type for listener: " + listener, ex);
  21. }
  22. }
  23. else {
  24. //抛出异常
  25. throw ex;
  26. }
  27. }
  28. }

SpringMVC中事件使用

SpringMVC中就是通过Spring的事件机制进行九大组件的初始化。

1.ContextRefreshListener监听器的定义

监听器定义在FrameworkServlet类中,作为内部类。代码如下:

  1. private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
  2. @Override
  3. public void onApplicationEvent(ContextRefreshedEvent event) {
  4. FrameworkServlet.this.onApplicationEvent(event);
  5. }
  6. }

监听器的添加在org.springframework.web.servlet.FrameworkServlet#configureAndRefreshWebApplicationContext 中进行。通过SourceFilteringListener进行包装。添加代码如下:

  1. // 添加监听器sourceFilteringListener到wac中,实际监听的是ContextRefreshListener所监听的事件,监听ContextRefreshedEvent事件,
  2. // 当接收到消息之后会调用onApplicationEvent方法,调用onRefresh方法,并将refreshEventReceived标志设置为true,表示已经refresh过
  3. wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

2.多播器添加已经定义的ContextRefreshListener事件监听器

在refresh中的registerListeners方法进行添加,代码如下:

  1. // Register statically specified listeners first.
  2. // 遍历应用程序中存在的监听器集合,并将对应的监听器添加到监听器的多路广播器中
  3. for (ApplicationListener<?> listener : getApplicationListeners()) {
  4. getApplicationEventMulticaster().addApplicationListener(listener);
  5. }

3.ContextRefreshListener事件监听器的触发

在refresh中的finishRefresh()方法中,会调用publishEvnet(new ContextRefreshedEvent(this))发布事件。进行多播器广播,代码如下

  1. // 多播applicationEvent到适当的监听器
  2. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

最终会调到FrameworkServlet.this.onApplicationEvent(event)。

  1. public void onApplicationEvent(ContextRefreshedEvent event) {
  2. // 标记 refreshEventReceived 为true
  3. this.refreshEventReceived = true;
  4. synchronized (this.onRefreshMonitor) {
  5. // 处理事件中的 ApplicationContext 对象,空实现,子类DispatcherServlet会实现
  6. onRefresh(event.getApplicationContext());
  7. }
  8. }
  1. @Override
  2. protected void onRefresh(ApplicationContext context) {
  3. initStrategies(context);
  4. }
  1. protected void initStrategies(ApplicationContext context) {
  2. // 初始化 MultipartResolver:主要用来处理文件上传.如果定义过当前类型的bean对象,那么直接获取,如果没有的话,可以为null
  3. initMultipartResolver(context);
  4. // 初始化 LocaleResolver:主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver),基于session的配置(SessionLocaleResolver),基于cookie的配置(CookieLocaleResolver)
  5. initLocaleResolver(context);
  6. // 初始化 ThemeResolver:主要用来设置主题Theme
  7. initThemeResolver(context);
  8. // 初始化 HandlerMapping:映射器,用来将对应的request跟controller进行对应
  9. initHandlerMappings(context);
  10. // 初始化 HandlerAdapter:处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器
  11. initHandlerAdapters(context);
  12. // 初始化 HandlerExceptionResolver:基于HandlerExceptionResolver接口的异常处理
  13. initHandlerExceptionResolvers(context);
  14. // 初始化 RequestToViewNameTranslator:当controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,spring将会采用约定好的方式提供一个逻辑视图名称
  15. initRequestToViewNameTranslator(context);
  16. // 初始化 ViewResolver: 将ModelAndView选择合适的视图进行渲染的处理器
  17. initViewResolvers(context);
  18. // 初始化 FlashMapManager: 提供请求存储属性,可供其他请求使用
  19. initFlashMapManager(context);
  20. }

Spring事件监听机制源码解析的更多相关文章

  1. SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)

    SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringApplicat ...

  2. 【spring源码学习】spring的事件发布监听机制源码解析

    [一]相关源代码类 (1)spring的事件发布监听机制的核心管理类:org.springframework.context.event.SimpleApplicationEventMulticast ...

  3. Spring事件监听ApplicationListener源码流程分析

    spring的事件机制是基于观察者设计模式的,ApplicationListener#onApplicationEvent(Event)方法,用于对事件的处理 .在容器初始化的时候执行注册到容器中的L ...

  4. Spring 事件监听机制及原理分析

    简介 在JAVA体系中,有支持实现事件监听机制,在Spring 中也专门提供了一套事件机制的接口,方便我们实现.比如我们可以实现当用户注册后,给他发送一封邮件告诉他注册成功的一些信息,比如用户订阅的主 ...

  5. Spring事件监听机制

    前言 Spring中的事件机制其实就是设计模式中的观察者模式,主要由以下角色构成: 事件 事件监听器(监听并处理事件) 事件发布者(发布事件) 首先看一下监听器和发布者的接口定义 public int ...

  6. SpringBoot事件监听机制及观察者模式/发布订阅模式

    目录 本篇要点 什么是观察者模式? 发布订阅模式是什么? Spring事件监听机制概述 SpringBoot事件监听 定义注册事件 注解方式 @EventListener定义监听器 实现Applica ...

  7. Spring的事件监听机制

    最近公司在重构广告系统,其中核心的打包功能由广告系统调用,即对apk打包的调用和打包完成之后的回调,需要提供相应的接口给广告系统.因此,为了将apk打包的核心流程和对接广告系统的业务解耦,利用了spr ...

  8. Spring ApplicationContext(八)事件监听机制

    Spring ApplicationContext(八)事件监听机制 本节则重点关注的是 Spring 的事件监听机制,主要是第 8 步:多播器注册:第 10 步:事件注册. public void ...

  9. JAVA 图形开发之计算器设计(事件监听机制)

    /*文章中用到的代码只是一部分,需要源码的可通过邮箱联系我 1978702969@qq.com*/ 前段时间刚帮同学用MFC写了个计算器,现在学到JAVA的图形开发,就试着水了一个计算器出来.(可以说 ...

随机推荐

  1. Solution -「多校联训」古老的序列问题

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\),和 \(q\) 次形如 \([L,R]\) 的询问,每次回答 \[\sum_{[l,r]\su ...

  2. MySQL 5.7 基于GTID主从复制+并行复制+半同步复制

    环境准备 IP HOSTNAME SERVICE SYSTEM 192.168.131.129 mysql-master1 mysql CentOS7.6 192.168.131.130 mysql- ...

  3. 【lwip】lwip源码基础

    目录 前言 概念&作用 网络接口 概念引入 总结 lwip netif 结构体 链接 字段分析 网卡链表 网络 IP 接收数据函数 发送数据函数 ARP 模块调用的发送函数 出口回调函数 用户 ...

  4. 多图|一文详解Nacos参数!

    Nacos 中的参数有很多,如:命名空间.分组名.服务名.保护阈值.服务路由类型.临时实例等,那这些参数都是什么意思?又该如何设置?接下来我们一起来盘它. 1.命名空间 在 Nacos 中通过命名空间 ...

  5. Devops 开发运维高级篇之Jenkins+Docker+SpringCloud微服务持续集成(上)

    Devops 开发运维高级篇之Jenkins+Docker+SpringCloud微服务持续集成(上) Jenkins+Docker+SpringCloud持续集成流程说明 大致流程说明: 1) 开发 ...

  6. 私有化轻量级持续集成部署方案--05-持续部署服务-Drone(上)

    提示:本系列笔记全部存在于 Github, 可以直接在 Github 查看全部笔记 持续部署概述 持续部署是能以自动化方式,频繁而且持续性的,将软件部署到生产环境.使软件产品能够快速迭代. 在之前部署 ...

  7. java操作excel(通过POI)

    读取所有数据,并打印出来,表单名:testcase 定义实体类(说明:这里单纯打印读取的excel内容,未用到实体类,反射的时候才会用到实体类) package com.qzcsbj; /** * @ ...

  8. 如何将k8s中的某些节点单独、仅给某些应用来使用

    1.概述 在k8s集群的使用场景中有这样的一种情况,某些机器只给某些特殊的应用来使用.那么,这个时候,需要有以下的2个条件来进行保障: 节点不允许其他的pod来使用 应用只允许被调度到该节点上 2.实 ...

  9. windev的字符集选择设置及元素命名方法建议

    windev支持多语言,且支持整站翻译,同时支持最终用户的多语言选择,可以说多语言功能已经非常的全面和强大. windev原生支持英语.法语和葡萄牙语,在使用如中文等非拉丁字母语言时,需要在多个地方进 ...

  10. 你的程序员女孩「GitHub 热点速览 v.22.09」

    本周最火的项目要数上周推荐的开源项目 How to Cook,火到一周涨了 18k+ star,但网友对它的定量烹饪方法褒贬不一.在本人看来,烹饪本就是一门"玄学",萝卜青菜各有所 ...