Spring中的观察者模式-事件监听

91 阅读12分钟

前言

观察者模式是GOF提出的23种设计模式之一,应用范围很广泛,网络上有太多资料介绍观察者模式,举例也很生动形象,理解起来并不困难。

百度百科这样定义观察者模式:观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

放到生活中的例子也有很多,例如,在微信上订阅了某个公众号,当公众号运营者发布新内容时,就会将消息推送到订阅者的微信上。

Spring中提供了一套事件监听机制(算是观察者模式的实现),既在内部使用,也对外提供给开发者使用,在日常开发中经常会用到。

例如如下代码:

 /**
  * 定义事件消息
  */
 public class MyApplicationEvent extends ApplicationEvent {
 ​
     private String message;
 ​
     public MyApplicationEvent(Object source, String message) {
         super(source);
         this.message = message;
     }
 ​
     public String getMessage() {
         return message;
     }
 ​
     public void setMessage(String message) {
         this.message = message;
     }
 }
 ​
 /**
  * 定义监听器,并且使用@Component注解,Spring会将该listener注册到广播器
  */
 @Component
 public class MyApplicationEventListener implements ApplicationListener<MyApplicationEvent> {
 ​
     @Override
     public void onApplicationEvent(MyApplicationEvent event) {
         System.out.println(event.getMessage() + ",停止交易!");
     }
 }
 ​
 /**
  * 业务类,感知了ApplicationContext之后,就可以使用applicationContext.publishEvent(event)在业务代码中发布事件消息了
  */
 @Service
 public class MyBiz implements ApplicationContextAware {
 ​
     private ApplicationContext applicationContext;
 ​
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
     }
 ​
     public void bizMethod(boolean foundPolice) {
         if (foundPolice) {
             // 自定义事件消息内容
             MyApplicationEvent event = new MyApplicationEvent(this, "有内鬼");
             // 发布事件消息
             applicationContext.publishEvent(event);
         }
     }
 }

当业务代码运行applicationContext.publishEvent(event)后,事件消息就会被Spring发布给监听器MyApplicationEventListener,打印出"有内鬼,停止交易!"

使用起来比较简单,但是Spring是如何实现这个过程的呢?下面通过解析源码来看看这个过程。

源码

源码基于Spring5.3.16版本,不同版本有轻微差异,整体逻辑一致。

Spring提供的事件监听机制,不仅仅供开发者在业务代码中使用,Spring源码内部也在大量使用。

这里不以Spring内部如何使用监听器为重点,以开发者业务逻辑使用监听器为重点,将事件监听机制的源码分为4个重要过程:

  1. Spring上下文对象AbstractApplicationContext初始化事件广播器ApplicationEventMulticaster
  2. 事件广播器注册监听器ApplicationListener
  3. 业务代码调用Spring上下文对象发布事件
  4. 广播器选择"感兴趣"的监听器,执行监听器处理事件的逻辑
1、初始化事件广播器

Spring容器在启动过程中,会进入Spring上下文对象的refresh()方法,这个方法很重要,因为其贯穿了整个容器的生命线。

给Spring上下文对象AbstractApplicationContext初始化事件广播器就是在refresh()方法其中一步完成的,具体位置是在initApplicationEventMulticaster()过程。

 // 代码位置:org.springframework.context.support.AbstractApplicationContext#refresh
 ​
 @Override
 public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
     // ...代码省略 
     try {
       // ...代码省略 
 ​
       // 初始化事件广播器
       initApplicationEventMulticaster();
 ​
       // ...代码省略
 ​
       // 注册监听器ApplicationListener
       registerListeners();
 ​
       // ...代码省略 
     }
     // ...代码省略
   }
 }
 ​
 protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   // 如果容器中存在"applicationEventMulticaster",那就获取返回
   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 {
     // 如果容器中不存在"applicationEventMulticaster",那就创建一个SimpleApplicationEventMulticaster
     // 并且赋值给上下文对象的applicationEventMulticaster属性
     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() + "]");
     }
   }
 }

方法initApplicationEventMulticaster()中,为Spring上下文对象AbstractApplicationContext的属性applicationEventMulticaster,初始化了一个事件广播器SimpleApplicationEventMulticaster,而SimpleApplicationEventMulticaster继承了抽象类AbstractApplicationEventMulticaster,所以这个广播器对象初始化完成后,内部会存在一个属性defaultRetriever,用于存储注册到广播器的listeners。

 /**
  * SimpleApplicationEventMulticaster继承了抽象类AbstractApplicationEventMulticaster
  */
 public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
   // ... 代码省略
 }
 ​
 public abstract class AbstractApplicationEventMulticaster
     implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
 ​
   // 存放监听器listeners的容器
   private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
 ​
   // ...代码省略
   
   /**
    * defaultRetriever添加listener的方式一,直接添加一个ApplicationListener对象,一般由Spring内部使用
    * 比如ApplicationContextClosedListener
    */
   @Override
   public void addApplicationListener(ApplicationListener<?> listener) {
     synchronized (this.defaultRetriever) {
       // 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();
     }
   }
 ​
   /**
    * 除了方式一以外,还支持基于beanName方式,添加listener,这种方式一般是业务中自定义Listener用到的
    * 当需要该listener时,会从容器获取或创建该beanName对应的listener bean
    * 比如上面代码示例中的MyApplicationEventListener
    */
   @Override
   public void addApplicationListenerBean(String listenerBeanName) {
     synchronized (this.defaultRetriever) {
       this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
       this.retrieverCache.clear();
     }
   }
   
   // ...代码省略
 }

由上面代码可见,初始化事件广播器完成后,容器中存在的几个重要对象的关系如下:

image-20221220185637995

2、注册监听器

同第1步初始化事件广播器一样,为事件广播器注册监听器listeners也是Spring在refresh()方法中完成的,在第1步中展示的refresh()源码中,已经通过注释指明了注册监听器的发生位置所在,即执行refresh()中的registerListeners()过程。

在这个过程中,会进行两种类型的listeners注册:

  • 一种是一般由Spring内部添加的listeners,通过调用addApplicationListener(ApplicationListener<?> listener)方法注册到事件广播器的listener;
  • 另一种是通过获取容器中的ApplicationListener类型的beanName,调用addApplicationListenerBean(String listenerBeanName)方法,将beanName先加入到事件广播器存储listeners的容器中,这些beanName对应的bean此时在容器中还未被创建,当后续需要用到listener的时候,会从容器中创建这个beanName对应的listener。代码示例中的MyApplicationEventListener就是通过这种方式。
 // 代码位置:org.springframework.context.support.AbstractApplicationContext#registerListeners
 ​
 protected void registerListeners() {
   // Register statically specified listeners first.
   for (ApplicationListener<?> listener : getApplicationListeners()) {
     // 第一种方式,直接注册listener类型的对象到事件广播器
     getApplicationEventMulticaster().addApplicationListener(listener);
   }
 ​
   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let post-processors apply to them!
   // 第二种方式,获取容器中此时存在的所有ApplicationListener类型的beanName
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
     // 将beanName注册到事件广播器 注意:getBeanNamesForType只是根据类型从BeanDefinition中获取beanName,并未创建出bean
     // 何时创建这些ApplicationListener bean?当需要监听器时,那何时需要监听器?即当发布事件到广播器时
     getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }
 ​
   // ...代码省略
 }
3、发布事件到事件广播器

前面两步都是Spring在内部帮我们完成的,初始化了一个广播器、注册了我们自定义的ApplicationListener。

那么如何在业务逻辑中发布事件?

如果能直接获取到Spring上下文对象AbstractApplicationContext中的SimpleApplicationEventMulticaster,那就调用这个对象的multicastEvent(ApplicationEvent event)就可以发布事件了。可是AbstractApplicationContext并没有提供给外部获取SimpleApplicationEventMulticaster的getter方法,SimpleApplicationEventMulticaster是Spring内部操作的对象。

AbstractApplicationContext中的SimpleApplicationEventMulticaster对象获取不到,那么该如何发布事件?

ApplicationContext类型对象是Spring提供给外部的上下文对象,里面封装了很多方便外部调用的接口,常见的例如,根据名称获取bean的方法getBean(String name),根据类型获取bean的方法getBean(Class<T> requiredType)等等,我们都是通过Spring上下文对象ApplicationContext完成的,但是实际上,Spring上下文对象只用来传递外部的方法调用,真正处理逻辑的是上下文对象中包含的各个组件,例如处理getBean方法,就是调用上下文对象包含的BeanFactory对象的getBean方法完成的。

为了外部很方便的使用事件监听机制,Spring也在上下文对象中提供了关于事件的一些方法:

  • addApplicationListener(ApplicationListener<?> listener) 给事件广播器注册监听器的方法
  • publishEvent(ApplicationEvent event) 发布事件方法

所以,发布事件只需要获取到Spring的上下文对象就行了,Spring提供了上下文感知接口ApplicationContextAware,方便业务逻辑中获取到Spring上下文对象。

 /**
  * 业务类,感知了ApplicationContext之后,就可以使用applicationContext.publishEvent(event)在业务代码中发布事件消息了
  */
 @Service
 public class MyBiz implements ApplicationContextAware {
 ​
     private ApplicationContext applicationContext;
 ​
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
     }
 ​
     public void bizMethod(boolean foundPolice) {
         if (foundPolice) {
           // 自定义事件消息内容
             MyApplicationEvent event = new MyApplicationEvent(this, "有内鬼");
             // 发布事件消息
             applicationContext.publishEvent(event);
         }
     }
 }
4、广播器选择监听器,处理事件

紧接着第3步,调用ApplicationContext对象的publishEvent(event)方法,上下文对象会将事件交给事件广播器,由事件广播器对象发布事件。

然后在事件广播器中选择对该事件"感兴趣"的监听器,处理事件。

通过上面第2步,可以知道广播器中注册了众多listeners,如何判断当前发布的事件是否是某个listener感兴趣的呢?然后交给这个listener去处理事件,这里是一个重点。

 // 代码位置:org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)
 ​
 @Override
 public void publishEvent(ApplicationEvent event) {
   publishEvent(event, null);
 }
 ​
 protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
   // ...代码省略
 ​
   // 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);
   }
 ​
   // ...代码省略
 }
 ​
 @Override
 public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   Executor executor = getTaskExecutor();
   // getApplicationListeners方法就是根据事件类型查找感兴趣的listener,这里标记为①
   // 然后一个个遍历返回的listener,处理事件
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
     if (executor != null) {
       // 如果executor不为空,支持异步调用listener执行事件处理逻辑
       executor.execute(() -> invokeListener(listener, event));
     }
     else {
       // 默认情况下executor没有配置,同步调用listener执行事件处理逻辑,这里标记为②
       invokeListener(listener, event);
     }
   }
 }
 ​
 // ① 
 // ps:①表示当前方法处于上面标记为①的方法栈中
 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);
 ​
   // Potential new retriever to populate
   CachedListenerRetriever newRetriever = null;
 ​
   // ...代码省略 为了快速多次快速获取listeners,Spring在这里设计了缓存,可以先不管
 ​
   // 检索对事件感兴趣的listeners
   return retrieveApplicationListeners(eventType, sourceType, newRetriever);
 }
 ​
 // ①
 private Collection<ApplicationListener<?>> retrieveApplicationListeners(
     ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
 ​
   // 本方法内的retriever变量是用来做缓存的,可以不关注retriever的逻辑
 ​
   List<ApplicationListener<?>> allListeners = new ArrayList<>();
   Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
   Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
 ​
   Set<ApplicationListener<?>> listeners;
   Set<String> listenerBeans;
   synchronized (this.defaultRetriever) {
     // 获取事件广播器中注册了的所有applicationListeners
     listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
     // 获取事件广播器中注册了的所有ApplicationListener类型的beanName列表
     listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
   }
 ​
   // Add programmatically registered listeners, including ones coming
   // from ApplicationListenerDetector (singleton beans and inner beans).
   for (ApplicationListener<?> listener : listeners) {
     // 先遍历注册的listeners,一个个判断listener是否支持当前事件,这里标记为③
     if (supportsEvent(listener, eventType, sourceType)) {
       if (retriever != null) {
         filteredListeners.add(listener);
       }
       // 如果支持,就是要找的listener,添加到要返回的allListeners列表
       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 {
         // 再遍历所有的ApplicationListener类型的beanName列表
         // 从容器中获取listenerBeanName对应的beanType,先通过判断beanType的泛型类型是否是eventType类型以及其父类型。
         // 因为这个过程不用实例化listenerBeanName对应的bean,可以避免创建不对事件感兴趣的listener
         // 标记为④
         if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
           // 根据listenerBeanName从容器中获取bean,如果容器中不存在就会创建bean
           ApplicationListener<?> listener =
               beanFactory.getBean(listenerBeanName, ApplicationListener.class);
           // listener已经有了,那就走和上面③位置一样的判断逻辑 supportsEvent(listener, eventType, sourceType)
           if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
             if (retriever != null) {
               if (beanFactory.isSingleton(listenerBeanName)) {
                 filteredListeners.add(listener);
               }
               else {
                 filteredListenerBeans.add(listenerBeanName);
               }
             }
             // 如果支持,就是要找的listener,添加到要返回的allListeners列表
             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) {
             filteredListeners.remove(listener);
           }
           allListeners.remove(listener);
         }
       }
       catch (NoSuchBeanDefinitionException ex) {
         // Singleton listener instance (without backing bean definition) disappeared -
         // probably in the middle of the destruction phase
       }
     }
   }
 ​
   // 对所有的listener排序,order数值越大,优先级越低
   AnnotationAwareOrderComparator.sort(allListeners);
   if (retriever != null) {
     if (filteredListenerBeans.isEmpty()) {
       retriever.applicationListeners = new LinkedHashSet<>(allListeners);
       retriever.applicationListenerBeans = filteredListenerBeans;
     }
     else {
       retriever.applicationListeners = filteredListeners;
       retriever.applicationListenerBeans = filteredListenerBeans;
     }
   }
   // 返回排序好的allListeners
   return allListeners;
 }
 ​
 // ① -> ③
 protected boolean supportsEvent(
     ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
   // 判断listener是否是GenericApplicationListener类型,如果不是,就包装成适配器类型GenericApplicationListenerAdapter
   // new GenericApplicationListenerAdapter()时,会初始化适配器对象的delegate、declaredEventType属性
   // delegate就是当前listener自身,declaredEventType是解析当前listener的泛型类型,封装成的一个ResolvableType对象
   // 例如上面示例代码 MyApplicationEventListener implements ApplicationListener<MyApplicationEvent>,declaredEventType就是获取ApplicationListener<MyApplicationEvent>中的泛型类型MyApplicationEvent,而封装的一个ResolvableType对象
   GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
       (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
   // 如果业务listener没有实现GenericApplicationListener,而是ApplicationListener(例如上面示例代码MyApplicationEventListener),就会进入GenericApplicationListenerAdapter的判断逻辑
   // GenericApplicationListenerAdapter对象执行"&&"后半段supportsSourceType(sourceType),默认返回true
   // 这里关注"&&"的前半段supportsEventType(eventType)
   return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
 }
 ​
 // ① -> ③
 @Override
 @SuppressWarnings("unchecked")
 public boolean supportsEventType(ResolvableType eventType) {
   // 这个方法分了三种情况,说明这个方法是个公共方法,紧跟着上面GenericApplicationListenerAdapter对象执行到这里,delegate就是一个ApplicationListener的普通实现类MyApplicationEventListener,会进入到else代码块中
   if (this.delegate instanceof GenericApplicationListener) {
     return ((GenericApplicationListener) this.delegate).supportsEventType(eventType);
   }
   else if (this.delegate instanceof SmartApplicationListener) {
     Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
     return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
   }
   else {
     // 即判断解析listener的泛型类型是否是事件类型以及事件类型的父类型
     return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
   }
 }
 ​
 // ① -> ④
 private boolean supportsEvent(
     ConfigurableBeanFactory beanFactory, String listenerBeanName, ResolvableType eventType) {
 ​
   // 从容器中获取beanName对应的beanType
   Class<?> listenerType = beanFactory.getType(listenerBeanName);
   if (listenerType == null || GenericApplicationListener.class.isAssignableFrom(listenerType) ||
       SmartApplicationListener.class.isAssignableFrom(listenerType)) {
     return true;
   }
   // supportEvent判断listener bean的泛型类型是否是eventType类型以及eventType类型的父类型
   // 举个例子就是:判断MyListener implements ApplicationListener<T>中的T类型是否是eventType类型以及eventType类型的父类型
   if (!supportsEvent(listenerType, eventType)) {
     return false;
   }
   try {
     BeanDefinition bd = beanFactory.getMergedBeanDefinition(listenerBeanName);
     // 这里有点不理解,上面supportsEvent已经判断了一次了,这里的逻辑和supportsEvent基本一致
     // 为什么还要再来一遍?
     ResolvableType genericEventType = bd.getResolvableType().as(ApplicationListener.class).getGeneric();
     return (genericEventType == ResolvableType.NONE || genericEventType.isAssignableFrom(eventType));
   }
   catch (NoSuchBeanDefinitionException ex) {
     // Ignore - no need to check resolvable type for manually registered singleton
     return true;
   }
 }

上面源码详细介绍了如何查找对事件感兴趣的listeners的经过,基本逻辑如下:

  1. 首先遍历广播器中已经注册的listeners,依次判断listeners是否对事件"感兴趣"。
  2. 其次遍历广播器中已经注册的ApplicationListener类型的beanName列表,依次判断beanName对应的beanType是否支持事件类型,如果支持,就获取或创建出该ApplicationListener bean,然后判断listener是否对事件"感兴趣"。

判断listener对象是否对发布的事件"感兴趣",以上面示例代码为例,MyApplicationEventListener implements ApplicationListener<MyApplicationEvent>,自定义listener直接实现了ApplicationListener接口,而非GenericApplicationListener、SmartApplicationListener类型对象,所以判断MyApplicationEventListener接口ApplicationListener上的泛型MyApplicationEvent类型是否是事件类型以及事件类型的父类型。当发布的事件类型为MyApplicationEvent时,MyApplicationEventListener自然就会被找到,处理这个事件。

找到感兴趣的listeners后,处理事件的逻辑入口在上面代码中标记为了②,这个逻辑比较简单,贴一下代码:

 // 代码位置:org.springframework.context.event.SimpleApplicationEventMulticaster#invokeListener
 ​
 protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
   ErrorHandler errorHandler = getErrorHandler();
   if (errorHandler != null) {
     try {
       doInvokeListener(listener, event);
     }
     catch (Throwable err) {
       errorHandler.handleError(err);
     }
   }
   else {
     // 调用listener的onApplicationEvent方法
     doInvokeListener(listener, event);
   }
 }
 ​
 private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
   try {
     // 调用listener的onApplicationEvent方法,由此进入我们自定义的listener逻辑
     listener.onApplicationEvent(event);
   }
   catch (ClassCastException ex) {
     // ...
   }
 }

第3、4步合起来,画一个简单的流程图,如下: image-20221221155125355