spring,springBoot事件

這個系列分爲5篇

引言

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原理

找入口

 

EventListenerMethodProcessor 就是處理@EventListener註解的入口類
找主要方法
查看 EventListenerMethodProcessor 的類註釋,簡要翻譯如下:

1.將@EventListener方法轉換爲ApplicationListener示例

2.實現BeanFactoryPostProcessor用於檢索EventListenerFactory

避免AOP增強,EventListenerFactory

在查看, EventListenerMethodProcessor的類圖

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的方法,
2.通過 EventListenerFactory轉換爲ApplicationListenerMethodAdapter,
3.該事件監聽器註冊上線文中。

 

@EventListener總結

1. EventListenerMethodProcessor 是@EventListener的生命週期處理器,實現了 SmartInitializingSingleton接口的afterSingletonsInstantiated 方法,進行了:
  • 這個方法的邏輯就是將@EventListener的方法,
  • 通過EventListenerFactory轉換爲ApplicationListenerMethodAdapter,
  • 該事件監聽器註冊上線文中。
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共用。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章