【Spring源码分析】20-ApplicationEvent事件机制

ApplicationContext提供事件处理通过ApplicationEvent类和ApplicationListener接口。如果一个bean实现ApplicationListener接口在容器中,每次一个ApplicationEvent被发布到ApplicationContext中,这类bean就会收到这些通知。从本质上讲,这是标准的观察者设计模式。

实现Spring事件机制主要有4个类:

  • ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。
  • ApplicationListener:事件监听器,用于接收事件处理时间。
  • ApplicationEventMulticaster:事件管理者,用于事件监听器的注册和事件的广播。
  • ApplicationEventPublisher:事件发布者,委托ApplicationEventMulticaster完成事件发布。

1、ApplicationEvent

事件就是一个包含了任意对象并含有事件对象创建时间戳的类。

public abstract class ApplicationEvent extends EventObject {
   private static final long serialVersionUID = 7099057708183571937L;
   private final long timestamp;
   public ApplicationEvent(Object source) {
      super(source);
      this.timestamp = System.currentTimeMillis();
   }
   public final long getTimestamp() {
      return this.timestamp;
   }
}

下表描述了Spring提供的标准事件:

Spring内置事件

事件描述

ContextRefreshedEvent

事件发布在ApplicationContext初始化或刷新时(例如,通过在ConfigurableApplicationContext接口使用refresh()方法)。这里,“初始化”意味着所有bean加载,post-processor bean被检测到并且激活,单例预先实例化,ApplicationContext对象可以使用了。只要上下文没有关闭,可以触发多次刷新,ApplicationContext提供了一种可选择的支持这种“热”刷新。例如,XmlWebApplicationContext支持热刷新,但GenericApplicationContext并非如此。具体是在AbstractApplicationContext的finishRefresh()方法中。

ContextStartedEvent

事件发布在ApplicationContext开始使用ConfigurableApplicationContext接口start()方法。这里,“开始”意味着所有生命周期bean接收到一个明确的起始信号。通常,这个信号用于明确停止后重新启动,但它也可以用于启动组件没有被配置为自动运行(例如,组件还没有开始初始化)。

ContextStoppedEvent

事件发布在ApplicationContext停止时通过使用ConfigurableApplicationContext接口上的stop()方法。在这里,“停止”意味着所有生命周期bean接收一个显式的停止信号。停止上下文可以通过重新调用start()方法。

ContextClosedEvent

事件发布在ApplicationContext关闭时通过关闭ConfigurableApplicationContext接口()方法。这里,“封闭”意味着所有单例bean被摧毁。一个封闭的环境达到生命的终结。它不能刷新或重启。

RequestHandledEvent

一个特定的web事件告诉所有能处理HTTP请求的bean 。这个事件是在请求完成后发布的。这个事件只适用于使用Spring的DispatcherServlet的web应用程序。

2、ApplicationListener

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
   void onApplicationEvent(E event);
}

当事件监听器接收到它可以处理的事件,会调用onApplicationEvent()方法。注意到ApplicationListener是泛型参数的这样可以参数化的定制事件。这意味着onApplicationEvent()方法可以保持类型安全,避免任何需要向下类型转换。你可以尽可能多的注册你希望事件侦听器,但是注意,默认情况下,事件监听器同步接收事件。这意味着publishEvent()方法会阻塞直到所有的事件监听器成处理完事件。这种单线程同步方法的一个特点是,当一个监听器接收到一个事件时,它运行在事务上下文的发布者线程上如果事务上下文可用。如果事件的发布需要另一种策略(譬如多线程)需要实现自己的 ApplicationEventMulticaster接口类。

3、ApplicationEventMulticaster

ApplicationEventMulticaster接口方法分为三类,注册事件监听器、移除事件监听器、发布事件。

public interface ApplicationEventMulticaster {
   void addApplicationListener(ApplicationListener<?> listener);
   void addApplicationListenerBean(String listenerBeanName);
   void removeApplicationListener(ApplicationListener<?> listener);
   void removeApplicationListenerBean(String listenerBeanName);
   void removeAllListeners();
   void multicastEvent(ApplicationEvent event);
   void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}

执行AbstractApplicationContext.initApplicationEventMulticaster() 方法时会实例化一个bean name为applicationEventMulticaster的SimpleApplicationEventMulticaster,它的父类实现了前5个方法依靠一个内部类ListenerRetriever维护了一个Set<ApplicationListener<?>>,本质事件监听器的注册或移除就是对这个Set的添加和移除操作。

public abstract class AbstractApplicationEventMulticaster
      implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
   private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
   
   @Override
   public void addApplicationListener(ApplicationListener<?> listener) {
      synchronized (this.retrievalMutex) {
         // Explicitly remove target for a proxy, if registered already,
         // in order to avoid double invocations of the same listener.
         Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
         if (singletonTarget instanceof ApplicationListener) {
            this.defaultRetriever.applicationListeners.remove(singletonTarget);
         }
         this.defaultRetriever.applicationListeners.add(listener);
         this.retrieverCache.clear();
      }
   }

   @Override
   public void removeApplicationListener(ApplicationListener<?> listener) {
      synchronized (this.retrievalMutex) {
         this.defaultRetriever.applicationListeners.remove(listener);
         this.retrieverCache.clear();
      }
   }

   private class ListenerRetriever {
      public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
      public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
      private final boolean preFiltered;
      public ListenerRetriever(boolean preFiltered) {
         this.preFiltered = preFiltered;
      }
      public Collection<ApplicationListener<?>> getApplicationListeners() {
         List<ApplicationListener<?>> allListeners = new ArrayList<>(
               this.applicationListeners.size() + this.applicationListenerBeans.size());
         allListeners.addAll(this.applicationListeners);
         if (!this.applicationListenerBeans.isEmpty()) {
            BeanFactory beanFactory = getBeanFactory();
            for (String listenerBeanName : this.applicationListenerBeans) {
               try {
                  ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                  if (this.preFiltered || !allListeners.contains(listener)) {
                     allListeners.add(listener);
                  }
               }
               catch (NoSuchBeanDefinitionException ex) {
                  // Singleton listener instance (without backing bean definition) disappeared -
                  // probably in the middle of the destruction phase
               }
            }
         }
         if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
            AnnotationAwareOrderComparator.sort(allListeners);
         }
         return allListeners;
      }
   }

}

接口后两个方法由子类实现,可以看到SimpleApplicationEventMulticaster拥有一个Executor和ErrorHandler,分表表示监听器的调用线程池(如果不想使用单线程同步处理则可以设置一个线程池)和监听器处理事件失败的处理者(如果设置了的话)否则抛异常。 

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
   @Nullable
   private Executor taskExecutor;
   @Nullable
   private ErrorHandler errorHandler;
   public SimpleApplicationEventMulticaster() {
   }
   public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
      setBeanFactory(beanFactory);
   }
   public void setTaskExecutor(@Nullable Executor taskExecutor) {
      this.taskExecutor = taskExecutor;
   }
   public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
      this.errorHandler = errorHandler;
   }
   @Override
   public void multicastEvent(ApplicationEvent event) {
      //广播事件,可以自动分析出ApplicationEvent是那种事件类型
      multicastEvent(event, resolveDefaultEventType(event));
   }
   @Override
   public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
      ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
      //调用父类方法getApplicationListeners只取得能处理此类事件的时间监听器,依次处理
      for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
         Executor executor = getTaskExecutor();
         if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
         }
         else {
            invokeListener(listener, event);
         }
      }
   }

   private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
      return ResolvableType.forInstance(event);
   }

   protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
      ErrorHandler errorHandler = getErrorHandler();
      if (errorHandler != null) {
         try {
            doInvokeListener(listener, event);
         }
         catch (Throwable err) {
            errorHandler.handleError(err);
         }
      }
      else {
         doInvokeListener(listener, event);
      }
   }

   @SuppressWarnings({"unchecked", "rawtypes"})
   private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
      try {
         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.isDebugEnabled()) {
               logger.debug("Non-matching event type for listener: " + listener, ex);
            }
         }
         else {
            throw ex;
         }
      }
   }

   private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {
      // On Java 8, the message starts with the class name: "java.lang.String cannot be cast..."
      if (classCastMessage.startsWith(eventClass.getName())) {
         return true;
      }
      // On Java 11, the message starts with "class ..." a.k.a. Class.toString()
      if (classCastMessage.startsWith(eventClass.toString())) {
         return true;
      }
      // On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
      int moduleSeparatorIndex = classCastMessage.indexOf('/');
      if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {
         return true;
      }
      // Assuming an unrelated class cast failure...
      return false;
   }

}

4、ApplicationEventPublisher

@FunctionalInterface
public interface ApplicationEventPublisher {
   default void publishEvent(ApplicationEvent event) {
      publishEvent((Object) event);
   }
   void publishEvent(Object event);
}

ApplicationEventPublisher很简单只有两个发布事件的方法,AbstractApplicationContext是它的默认实现类,下面是具体实现。

@Override
public void publishEvent(ApplicationEvent event) {
   publishEvent(event, null);
}
@Override
public void publishEvent(Object event) {
   publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
   Assert.notNull(event, "Event must not be null");

   // Decorate event as an ApplicationEvent if necessary
   ApplicationEvent applicationEvent;
   if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent) event;
   }
   else {
      applicationEvent = new PayloadApplicationEvent<>(this, event);
      if (eventType == null) {
         eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
      }
   }

   // Multicast right now if possible - or lazily once the multicaster is initialized
   if (this.earlyApplicationEvents != null) {
      this.earlyApplicationEvents.add(applicationEvent);
   }
   else {
      getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
   }

   // Publish event via parent context as well...
   if (this.parent != null) {
      if (this.parent instanceof AbstractApplicationContext) {
         ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
      }
      else {
         this.parent.publishEvent(event);
      }
   }
}

可以看到事件的发布依赖于前面提到的bean name是applicationEventMulticaster的SimpleApplicationEventMulticaster。

5、事件监听器的注册

在AbstractApplicationContext.prepareBeanFactory()方法执行的时候会添加一个BeanPostProcessor–>ApplicationListenerDetector,它实现了MergedBeanDefinitionPostProcessor接口,在postProcessAfterInitialization()方法执行的时候检测已注册到容器中的bean如果是ApplicationListener,就通过applicationContext添加。

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
   if (bean instanceof ApplicationListener) {
      // potentially not detected as a listener by getBeanNamesForType retrieval
      Boolean flag = this.singletonNames.get(beanName);
      if (Boolean.TRUE.equals(flag)) {
         // singleton bean (top-level or inner): register on the fly
         this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
      }
      else if (Boolean.FALSE.equals(flag)) {
         if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
            // inner bean with other scope - can't reliably process events
            logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
                  "but is not reachable for event multicasting by its containing ApplicationContext " +
                  "because it does not have singleton scope. Only top-level listener beans are allowed " +
                  "to be of non-singleton scope.");
         }
         this.singletonNames.remove(beanName);
      }
   }
   return bean;
}

自Spring 4.2起,事件机制明显改善,提供了一个基于注解的模型以及发布任意事件的能力。基于注解的Spring启动形式会在AnnotationConfigBeanDefinitionParser.parse(Element, ParserContext)方法内部注册一个bean name为org.springframework.context.event.internalEventListenerProcessor的EventListenerMethodProcessor。这个bean实现了SmartInitializingSingleton接口,在接口方法afterSingletonsInstantiated()调用时会检测容器内所有的bean,如果发现有@EventListener方法将使用容器内EventListenerFactory将此@EventListener方法包装一个ApplicationListener放入容器中。

@Override
public void afterSingletonsInstantiated() {
   ConfigurableListableBeanFactory beanFactory = this.beanFactory;
   Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
   String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
   for (String beanName : beanNames) {
      //如果一个类被代理,那么处理它的代理类即可
      if (!ScopedProxyUtils.isScopedTarget(beanName)) {
         Class<?> type = null;
         try {
            //代理模式需要取得目标类,然后取得目标类上@EventListener方法
            type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
         }
         catch (Throwable ex) {
            // An unresolvable bean type, probably from a lazy bean - let's ignore it.
            if (logger.isDebugEnabled()) {
               logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
            }
         }
         if (type != null) {
            if (ScopedObject.class.isAssignableFrom(type)) {
               try {
                  Class<?> targetClass = AutoProxyUtils.determineTargetClass(
                        beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
                  if (targetClass != null) {
                     type = targetClass;
                  }
               }
               catch (Throwable ex) {
                  // An invalid scoped proxy arrangement - let's ignore it.
                  if (logger.isDebugEnabled()) {
                     logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
                  }
               }
            }
            try {
               //解析@EventListener方法的类,注册事件监听器
               processBean(beanName, type);
            }
            catch (Throwable ex) {
               throw new BeanInitializationException("Failed to process @EventListener " +
                     "annotation on bean with name '" + beanName + "'", ex);
            }
         }
      }
   }
}

private void processBean(final String beanName, final Class<?> targetType) {
   //缓存防止重复注册
   //只解析用户定义的类
   if (!this.nonAnnotatedClasses.contains(targetType) && !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) {
               //使用Spring容器中第一个能解析此@EventListener方法的EventListenerFactory
               if (factory.supportsMethod(method)) {
                  Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                  //使用EventListenerFactory将@EventListener解析为一个ApplicationListener后加入容器
                  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);
         }
      }
   }
}

上面的代码核心部分就是processBean()方法,内部使用容器第一个可能解析当前@EventListener的EventListenerFactory创建一个ApplicationListener用来处理@EventListener指定的类型事件。下面就是看看Spring容器都有哪些EventListenerFactory,和EventListenerFactory是如何创建ApplicationListener的?

EventListenerFactory的注册和EventListenerMethodProcessor一样在AnnotationConfigBeanDefinitionParser.parse(Element, ParserContext)方法内,bean name为org.springframework.context.event.internalEventListenerFactory,是DefaultEventListenerFactory。

public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
   private int order = LOWEST_PRECEDENCE;
   public void setOrder(int order) {
      this.order = order;
   }
   @Override
   public int getOrder() {
      return this.order;
   }
   public boolean supportsMethod(Method method) {
      return true;
   }
   @Override
   public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
      return new ApplicationListenerMethodAdapter(beanName, type, method);
   }
}

DefaultEventListenerFactory支持所有的方法成为ApplicationListener,下面看createApplicationListener()方法返回的ApplicationListenerMethodAdapter是如何处理@EventListener指定的事件的。

public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
   this.beanName = beanName;
   this.method = BridgeMethodResolver.findBridgedMethod(method);
   this.targetMethod = (!Proxy.isProxyClass(targetClass) ?
         AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
   this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);

   EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
   this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
   this.condition = (ann != null ? ann.condition() : null);
   this.order = resolveOrder(method);
}

declaredEventTypes是指事件监听器能够支持的事件类型。

private List<ResolvableType> resolveDeclaredEventTypes(Method method, @Nullable EventListener ann) {
   //注意方法参数最多只能有一个
   int count = method.getParameterCount();
   if (count > 1) {
      throw new IllegalStateException(
            "Maximum one parameter is allowed for event listener method: " + method);
   }

   if (ann != null) {
      Class<?>[] classes = ann.classes();
      if (classes.length > 0) {
         List<ResolvableType> types = new ArrayList<>(classes.length);
         for (Class<?> eventType : classes) {
            types.add(ResolvableType.forClass(eventType));
         }
         return types;
      }
   }

   if (count == 0) {
      throw new IllegalStateException(
            "Event parameter is mandatory for event listener method: " + method);
   }
   return Collections.singletonList(ResolvableType.forMethodParameter(method, 0));
}

​​​​​​​@Override
public boolean supportsEventType(ResolvableType eventType) {
   for (ResolvableType declaredEventType : this.declaredEventTypes) {
      if (declaredEventType.isAssignableFrom(eventType)) {
         return true;
      }
      if (PayloadApplicationEvent.class.isAssignableFrom(eventType.toClass())) {
         ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
         if (declaredEventType.isAssignableFrom(payloadType)) {
            return true;
         }
      }
   }
   return eventType.hasUnresolvableGenerics();
}

处理事件的大致逻辑为,事件作为@EventListener方法的参数(如果是PayloadApplicationEvent则使用payload作为参数),然后执行该方法,如果有返回值则继续讲返回值作为事件发布。注意返回值是数组或集合会将集合内所有的元素单独发布。

@Override
public void onApplicationEvent(ApplicationEvent event) {
   processEvent(event);
}
public void processEvent(ApplicationEvent event) {
   Object[] args = resolveArguments(event);
   if (shouldHandle(event, args)) {
      Object result = doInvoke(args);
      if (result != null) {
         handleResult(result);
      }
      else {
         logger.trace("No result object given - no result to handle");
      }
   }
}
private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
   if (args == null) {
      return false;
   }
   String condition = getCondition();
   if (StringUtils.hasText(condition)) {
      Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");
      return this.evaluator.condition(
            condition, event, this.targetMethod, this.methodKey, args, this.applicationContext);
   }
   return true;
}
protected void handleResult(Object result) {
   if (result.getClass().isArray()) {
      Object[] events = ObjectUtils.toObjectArray(result);
      for (Object event : events) {
         publishEvent(event);
      }
   }
   else if (result instanceof Collection<?>) {
      Collection<?> events = (Collection<?>) result;
      for (Object event : events) {
         publishEvent(event);
      }
   }
   else {
      publishEvent(result);
   }
}

由shouldHandle()方法可知,@EventListener的condition属性决定着事件可否被处理。condition的值为SpEL,代表true才可被处理。下表列出了项目可用的上下文,这样您就可以使用这些条件事件处理:

事件SpEL可用的元对象

名称所在位置描述例子

Event

root object

实际的ApplicationEvent.

#root.event

Arguments array

root object

执行目标方法的参数数组

#root.args[0]

Argument name

evaluation context

任何方法参数的名称。出于某种原因,如果名字不是可用的(例如,因为没有调试信息),参数名称也可以使用这种形式 #a<#arg>,#arg代表参数索引(从0开始)。

#blEvent or #a0 (也可使用 #p0 或 #p<#arg>符号作为一个别名)

@EventListener(condition = "#blEvent.content == 'my-event'")
public void processBlackListEvent(BlackListEvent blEvent) {
    // notify appropriate parties via notificationAddress...
}

 

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/shenchaohao12321/article/details/85303453
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞