spring,springBoot事件

这个系列分为5篇

1. @Component,@Service等注解是如何被解析

2. @Enableq驱动原理(最晚20200705)

3. @EnableAutoConfiguration处理逻辑

4. spring,springBoot事件

5.自定义springboot starter(最晚20200726)

引言

spring事件机制,有3个核心部分,事件,监听方式,广播器,下面我们分别介绍。

Spring事件

spring的事件的API对应ApplicationEvent。它继承了ava.util.EventObject。显示调用父类构造器传递事件源。

public abstract class ApplicationEvent extends EventObject {
	    ///省略其他代码
		public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
		}
       //省略其他代码
}复制代码

Spring内置事件

事件名 注释
ContextRefreshedEvent Spring应用上下文就绪事件
ContextStartedEvent Spring应用上下文启动事件
ContextStopedEvent Spring应用上下文停止事件
ContextClosedEvent Spring应用上下文关闭事件

允许泛型事件自定义,如果有兴趣可以参看: org.springframework.context.PayloadApplicationEvent

Spring事件监听手段

2种监听手段

1. 实现ApplicationListener接口 或 @EventListener,可监听1到多种事件,支持泛型事件

2. @EventListener方法上@Async,可使用@EventListener方法异步化,但是被注解的方法的返回值应该为void,其实返回值没有意义。

表@EventListener的同步与异步区别

方法类型 访问修饰符 返回类型 参数数量 参数类型 备注
同步 public 任意类型 0或1

监听事件类

型或其子类

会将返回值

作为事件向

后传播

异步 public void 0或1

监听事件类

型或其子类

如果出错不

会传播给调

用者。

不会向后传

播事件

@EventListener原理

找入口

spring,springBoot事件

EventListenerMethodProcessor 就是处理@EventListener注解的入口类

找主要方法

查看
EventListenerMethodProcessor 的类注释,简要翻译如下:

1.将@

EventListener方法转换为

ApplicationListener示例

2.实现

BeanFactoryPostProcessor用于检索

EventListenerFactory

避免AOP增强,EventListenerFactory

在查看, EventListenerMethodProcessor的类图

spring,springBoot事件

ApplicationContextAware 用于注入ApplicationContext。

BeanFactoryPostProcessor根据类注释可知用于获取EventListenerFactory。

这里最需要关注的应该是SmartInitializingSingleton#afterSingletonsInstantiated方法。

查看该方法的注释

public interface SmartInitializingSingleton {

   /**
    * 预实例化完成之后调用,保证所有常规单例Bean创建完毕
    * 调用ListableBeanFactory#getBeansOfType没有任何副作用
    * 注意: 
    * 对于延迟加载的单例Bean,不会触发这个回调。
    * 并且其他作用域的Bean,也不会触发这个回调。
    * 谨慎使用,应仅用于引导功能。
    */
   void afterSingletonsInstantiated();
}复制代码

afterSingletonsInstantiated 从方法注释上可以看出,这个方法可以用于引导功能。

查看源码EventListenerMethodProcessor ,逻辑就是找BeanName和Bean对应的Type,具体逻辑委托给 processBean,下面是processBean的源码

public class EventListenerMethodProcessor {
    //省略其他部分
private void processBean(final String beanName, final Class<?> targetType) {
   if (!this.nonAnnotatedClasses.contains(targetType) &&
         !targetType.getName().startsWith("java") &&
         !isSpringContainerClass(targetType)) {

      Map<Method, EventListener> annotatedMethods = null;
      try {
          //找出所有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)) {
         this.nonAnnotatedClasses.add(targetType);
         if (logger.isTraceEnabled()) {
            logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
         }
      }
      else {
         // Non-empty set of methods
         ConfigurableApplicationContext context = this.applicationContext;
         Assert.state(context != null, "No ApplicationContext set");
         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转换为ApplicationListenerMethodAdapter
                   ApplicationListener<?> applicationListener =
                        factory.createApplicationListener(beanName, targetType, methodToUse);
                  if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                     ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                  }
                  //将该事件监听器注册到应用上下文中。
                  context.addApplicationListener(applicationListener);
                  break;
               }
            }
         }
         if (logger.isDebugEnabled()) {
            logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                  beanName + "': " + annotatedMethods);
         }
      }
   }
}
}复制代码

AopUtils.selectInvocableMethod 是不允许访问,私有方法,静态方法,代理的方法,也就印证了 @EventListener 必须用public修饰

概要逻辑

1.这个方法的逻辑就是将@EventListener的方法,

EventListenerFactory转换为

3.该事件监听器注册上线文中。

@EventListener总结

1. EventListenerMethodProcessor 是@EventListener的生命周期处理器,实现了 SmartInitializingSingleton接口的afterSingletonsInstantiated 方法,进行了:

  • 这个方法的逻辑就是将@EventListener的方法,
  • EventListenerFactory转换为

  • 该事件监听器注册上线文中。

2. DefaultEventListenerFactory是@EventListener方法与ApplicationListener的适配工厂

3. ApplicationListenerMethodAdapter为适配类。

Spring的广播器

广播器为ApplicationEventMulticaster,它的默认实现为SimpleApplicationEventMulticaster

它主要有2个责任,维护ApplicationListener关联关系这个比较简单,我们关注下广播消息。

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

调用getApplicationListeners,遍历调用onApplicationEvent(ApplicationEvent)。

查看getApplicationListeners方法在其父类 AbstractApplicationEventMulticaster中。

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

   Object source = event.getSource();
   Class<?> sourceType = (source != null ? source.getClass() : null);
   ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

   // Quick check for existing entry on ConcurrentHashMap...
   ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
   if (retriever != null) {
      return retriever.getApplicationListeners();
   }

   if (this.beanClassLoader == null ||
         (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
               (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
      // Fully synchronized building and caching of a ListenerRetriever
      synchronized (this.retrievalMutex) {
         retriever = this.retrieverCache.get(cacheKey);
         if (retriever != null) {
            return retriever.getApplicationListeners();
         }
         retriever = new ListenerRetriever(true);
         Collection<ApplicationListener<?>> listeners =
               retrieveApplicationListeners(eventType, sourceType, retriever);
         this.retrieverCache.put(cacheKey, retriever);
         return listeners;
      }
   }
   else {
      // No ListenerRetriever caching -> no synchronization necessary
      return retrieveApplicationListeners(eventType, sourceType, null);
   }
}复制代码

内部维护一个final Map<ListenerCacheKey, ListenerRetriever> retrieverCache 维护事件类型与数据源的类型

ListenerCacheKey为eventType(对应泛型或者事件类本身) 和sourceType(ApplicationEvent构造器中的source),(对应ApplicationEvent)。

SimpleApplicationEventMulticaster总结:

1. SimpleApplicationEventMulticaster承担2个职责,关联ApplicationListener,广播ApplicationEvent。

2。 SimpleApplicationEventMulticaster 内部维护一个final Map<ListenerCacheKey, ListenerRetriever> retrieverCache 维护事件类型与数据源的类型

3. ListenerCacheKey为eventType(对应泛型或者事件类本身) 和sourceType(ApplicationEvent构造器中的source)

4. ListenerRetriever是AbstractApplicationEventMulticaster的内部类,对应ApplicationListener集合

5 .ApplicationEventMulticaster广播事件,multicastEvent(ApplicationEvent)和multicastEvent(ApplicationEvent,ResolvableType)

内部调用getApplicationListeners,遍历调用onApplicationEvent(ApplicationEvent)

补充说明:

通过ApplicationEventPublisherAware获得的ApplicationEventPublisher,是什么?

解决这个,就需要查看ApplicationContextAwareProcessor#postProcessBeforeInitialization

内部调用了 invokeAwareInterfaces方法,处理各种Aware接口的注入逻辑。

private void invokeAwareInterfaces(Object bean) {
   if (bean instanceof EnvironmentAware) {
      ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
   }
   if (bean instanceof EmbeddedValueResolverAware) {
      ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
   }
   if (bean instanceof ResourceLoaderAware) {
      ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
   }
   if (bean instanceof ApplicationEventPublisherAware) {
      ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
   }
   if (bean instanceof MessageSourceAware) {
      ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
   }
   if (bean instanceof ApplicationContextAware) {
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
   }
}复制代码

看到这里,答案就有了。ApplicationEventPublisherAware所获得的ApplicationEventPublisher实例就是当前的ApplicationContext。

简述Spring Boot事件

Springboot事件

SpringBoot事件继承ApplicationEvent,也是SpringApplicationEvent的子类

SpringBoot事件源是SpringApplication,内部事件根据EventPublishingRunListener的生命周期回调方法依次发布。

ApplicationStartingEvent 1.5出现

ApplicationEnvironmentPreparedEvent

ApplicationPreparedEvent

ApplicationStartedEvent

ApplicationReadyEvent, spring应用上下文之后发布

ApplicationFailedEvent, spring应用上下文之后发布

Spring Boot事件监听手段

SpringApplication关联的SpringApplication关联ApplicationListener

1.class-path下,META-INF/spring.factories资源中的ApplicationListener对象集合

2.SpringApplication#addListeners(…)或SpringApplicationBuilder#listeners(…)显示装配

Spring Boot的广播器

SimpleApplicationEventMulticaster,是特定的,2.0以后不与spring framework共用。

原文 

https://juejin.im/post/5f126f1de51d45347246bdf1

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » spring,springBoot事件

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址