Spring事件发布/监听机制

观察者模式

Spring中实现的观察者模式包含三部分:Event事件(相当于消息)、Listener监听者(相当于观察者)、Publisher发送者(相当于被观察者)

Spring实现方式

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

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

Spring中的事件:ApplicationEvent

观察者模式中传播的数据比较抽象,如Observable可发布任意的Object,而事件/监听器模式所发布的内容则有类型限制,在Java中他必须是java.util.EventObject对象,Spring事件抽象类ApplicationEvent必然扩展EventObject。

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中的事件监听者:ApplicationListener

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

Spring事件监听器,仅抽象单一方法onApplicationEvent(ApplicaiotnEvent)将其用于监听Spring事件ApplicationEvent。

你可以尽可能多的注册你希望事件侦听器,但是注意,默认情况下,事件监听器同步接收事件。这意味着publishEvent()方法会阻塞直到所有的事件监听器成处理完事件。

这种单线程同步方法的一个特点是,当一个监听器接收到一个事件时如果事务上下文可用,它运行在事务上下文的发布者线程上。
如果事件的发布需要另一种策略(譬如多线程)需要实现自己的 ApplicationEventMulticaster接口类。

Spring提供了SmartApplicationListener接口解决泛型参数的限制:泛型化的ApplicationListener无法监听不同类型的ApplicationEvent,如ApplicationListener无法同时监听ContextStartedEvent。如果继续使用ApplicationListener又会有上述的问题。

public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
    //确定此监听器是否实际支持给定的事件类型。
    boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
 
    default boolean supportsSourceType(@Nullable Class<?> sourceType) {
        return true;
    }
    @Override
    default int getOrder() {
        return LOWEST_PRECEDENCE;
    }
}

该接口通过supportsXXXXType方法过滤需要监听的ApplicationEvent类型和事件源类型,从而达到监听不同类型的
ApplicationEvent的目的。

SmartApplicationListener是Spring3.0引入的,在4.2又引入了一个GenericApplicationListener可用来代替
SmartApplicationListener,它的supportsEventType方法的参数是一个ResolvableType,更加全面的支持泛型化。

public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
 
    boolean supportsEventType(ResolvableType eventType);

    default boolean supportsSourceType(@Nullable Class<?> sourceType) {
        return true;
    }
    @Override
    default int getOrder() {
        return LOWEST_PRECEDENCE;
    }
}

Spring事件监听器注册/事件广播:ApplicationEventMulticaster

默认情况下Spring使用SimpleApplicationEventMulticaster广播事件,它是ApplicationEventMulticaster接口的实现类,
该接口主要承担两种职责,一是关联ApplicationListener、二是广播ApplicationEvent。

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);
}

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) {
         // 如果已经注册,则显式删除代理的目标,以避免对同一个侦听器进行双重调用。
         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;
      }
   }
  
}

接口后两个方法(用于广播的两个multicastEvent方法)由子类实现,可以看到 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;
         }
      }
   }
  
}

SimpleApplicationEventMulticaster在进行广播时,调用父类方法AbstractApplicationEventMulticaster.getApplicationListeners(ApplicationEvent, ResolvableType)返回一组能够处理当前事件类型的事件监听器,依次去调用事件监听器的onApplicationEvent方法默认是同步调用,也可以通过setTaskExecutor方法传入一个Executor来达到异步处理的方式。

下面重点看一下AbstractApplicationEventMulticaster#getApplicationListeners(ApplicationEvent, ResolvableType)和retrieveApplicationListeners(ResolvableType, Class, ListenerRetriever )

public class 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);
       }
    }

    //上面代码主要检索缓存中是否存在,实际上为给定事件和源类型检索应用程序监听器的是retrieveApplicationListeners方法。
    private Collection<ApplicationListener<?>> retrieveApplicationListeners(
          ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
      
       List<ApplicationListener<?>> allListeners = new ArrayList<>();
       Set<ApplicationListener<?>> listeners;
       Set<String> listenerBeans;
       synchronized (this.retrievalMutex) {
          listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
          listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
       }
      
       // Add programmatically registered listeners, including ones coming
       // from ApplicationListenerDetector (singleton beans and inner beans).
       for (ApplicationListener<?> listener : listeners) {
          //GenericApplicationListener、SmartApplicationListener通过supportsXXX方法
          //普通ApplicationListener通过具体事件类型过滤
          if (supportsEvent(listener, eventType, sourceType)) {
             if (retriever != null) {
                retriever.applicationListeners.add(listener);
             }
             allListeners.add(listener);
          }
       }
      
       // Add listeners by bean name, potentially overlapping with programmatically
       // registered listeners above - but here potentially with additional metadata.
       if (!listenerBeans.isEmpty()) {
          ConfigurableBeanFactory beanFactory = getBeanFactory();
          for (String listenerBeanName : listenerBeans) {
             try {
                if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
                   ApplicationListener<?> listener =
                         beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                   if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                      if (retriever != null) {
                         if (beanFactory.isSingleton(listenerBeanName)) {
                            retriever.applicationListeners.add(listener);
                         }
                         else {
                            retriever.applicationListenerBeans.add(listenerBeanName);
                         }
                      }
                      allListeners.add(listener);
                   }
                }
                else {
                   // Remove non-matching listeners that originally came from
                   // ApplicationListenerDetector, possibly ruled out by additional
                   // BeanDefinition metadata (e.g. factory method generics) above.
                   Object listener = beanFactory.getSingleton(listenerBeanName);
                   if (retriever != null) {
                      retriever.applicationListeners.remove(listener);
                   }
                   allListeners.remove(listener);
                }
             }
             catch (NoSuchBeanDefinitionException ex) {
                // Singleton listener instance (without backing bean definition) disappeared -
                // probably in the middle of the destruction phase
             }
          }
       }
      
       AnnotationAwareOrderComparator.sort(allListeners);
       if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
          retriever.applicationListeners.clear();
          retriever.applicationListeners.addAll(allListeners);
       }
       return allListeners;
    }

}

Spring事件发布:ApplicationEventPublisher

ApplicationEventPublisher仅存在两个发布ApplicationEvent的重载方法publishEvent,并无关联ApplicationListener的操作方法。
不过ApplicationEventPublisher接口被接口ApplicationContext扩展因此无论使用哪种ApplicationContext实例均具备发布
ApplicationEvent的能力
。同时ApplicationContext的子接口ConfigurableApplicationContext提供了添加
ApplicationListener实例的关联方法addApplicationListener(ApplicationListener)。

@Override
public void addApplicationListener(ApplicationListener<?> listener) {
   Assert.notNull(listener, "ApplicationListener must not be null");
   if (this.applicationEventMulticaster != null) {
      this.applicationEventMulticaster.addApplicationListener(listener);
   }
   this.applicationListeners.add(listener);
}

可以看到通过ConfigurableApplicationContext的addApplicationListener方法注册事件监听器也会注册到内部成员变量
applicationEventMulticaster中。

既然ApplicationContext对象是ApplicationEventPublisher实例,则不难发现AbstractApplicationContext完全实现了
ApplicationEventPublisher接口:

public abstract class 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);
          }
       }
    }

}

明显地在publishEvent(Object,ResolvableType)方法中显示地调用了getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType),而applicationEventMulticaster属性又由initApplicationEventMulticaster()方法初始化。

//AbstractApplicationContext
protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isTraceEnabled()) {
         logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }
   else {
      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() + "]");
      }
   }
}

在applicationEventMulticaster初始化中首先判断Spring应用上下文是否存在名为applicationEventMulticaster且类型为ApplicationEventMulticaster的bean,如果不存在则将其构造为SimpleApplicationEventMulticaster对象注册到Spring容器中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值