浅谈Spring Framework中的设计模式,学会优雅地编程!

71 阅读16分钟

Spring Framework简单介绍

Spring 是面向 Bean 编程的 Java 应用程序框架(BOP: Bean Oriented Programming)。Bean 在 Spring 中才是真正的主角。Bean 在 Spring 中作用就像 Object 对 OOP 的意义一样,没有对象的概念就像没有面向对象编程,Spring 中没有 Bean 也就没有 Spring 存在的意义。Spring 提供了 IoC 容器通过配置文件或者注解的方式来管理对象之间的依赖关系,取代了繁琐的使用 new 关键字反复创建对象,实现了对象的复用。但是,Spring 的依赖注入是通过运行时反射实现的,所以性能会比较受到影响,不如那些代码生成式的框架性能高。

控制反转(Inversion of Control,缩写为 IoC),是面向对象编程中的一种设计原则,可以用来减低代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称 DI)。还有一种说法叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的实体,将其所依赖的对象的引用传递给它。

Spring Framework的Bean组件

Spring 的 Bean 组件定义在 org.springframework.beans 包下面,这个包的所有类主要解决了三件事:

  1. Bean 的定义。
  2. Bean 的创建。
  3. Bean 的解析。

Spring Bean 的创建是典型的工厂模式,它的顶层接口是 BeanFactory

image.png

BeanFactory 有三个子类:ListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactory。目的是为了区分Spring内部对象处理和转化的数据限制

但是从图中可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。

Spring Framework的工厂模式

Spring的BeanFactory接口

Spring 中的 BeanFactory 就是简单工厂模式的体现,根据传入一个唯一的标识来获得 Bean 对象。

BeanFactory,以 Factory 结尾,表示它是一个工厂(接口), 它负责生产和管理 Bean 的一个工厂。在 Spring中,BeanFactory 是工厂的顶层接口,也是 IOC 容器的核心接口,因此 BeanFactory 中定义了管理Bean的通用方法,如 getBeancontainsBean 等。

它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

Bean的创建流程

BeanFactory 只是个接口,并不是 IOC 容器的具体实现,所以 Spring 容器给出了很多种实现,如 DefaultListableBeanFactoryXmlBeanFactoryApplicationContext 等,其中DefaultListableBeanFactory 就是常用的一个,该实现将以 XML 方式描述组成应用的对象及对象间的依赖关系。

BeanFactory源码解析

public interface BeanFactory {

   /**
    * 转义符,如果根据 name 来获取 Bean 对象,那么对于 FactoryBean 来说将会返回它生产的实例,而不是
    * FactoryBean 本身。要获取 FactoryBean 本身那么就需要使用转义符 &。
    */
   String FACTORY_BEAN_PREFIX = "&";

   /**
    * 根据 name 返回 Bean 对象。
    */
   Object getBean(String name) throws BeansException;

   /**
    * 根据 name 返回 Bean 对象,加上了泛型,不需要强转 Object 了。增加了类型安全机制。
    */
   <T> T getBean(String name, Class<T> requiredType) throws BeansException;

   /**
    * 使用构造方法参数获取一个 Bean 对象。
    */
   Object getBean(String name, Object... args) throws BeansException;

   /**
    * 根据类型获取 Bean 对象。
    */
   <T> T getBean(Class<T> requiredType) throws BeansException;

   <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
   
   <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

   <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

   boolean containsBean(String name);

   /**
    * 根据名称判断是否是单例。
    */
   boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

   /**
    * 根据名称判断是否是原型。
    */
   boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
   
   /**
    * 根据名称判断是否类型匹配。
    */
   boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

   boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

   @Nullable
   Class<?> getType(String name) throws NoSuchBeanDefinitionException;

   /**
    * 获取 Bean 的类型,第二个 boolean 参数为 true 表示假如事先没有初始化的 FactoryBean 的话会初始化。
    */
   @Nullable
   Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

   /**
    * 获取别名
    */
   String[] getAliases(String name);

}

BeanFactory 的使用场景:

  • 从 IOC 容器中获取 Bean(Name or Type)。
  • 检索 IOC 容器中是否包含了指定的对象。
  • 判断 Bean 是否为单例。

BeanFactory的简单使用

定义 pojo:

@Data
public class User {
    
    private Integer id;
    
    private String name;
    
    private Friends friends;

}

@Data
public class Friends {
    
    private List<String> names;

}

编写 application-context/xml Bean 的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user1" class="org.codeart.springdemo.pojo.User">
        <property name="id" value="100"/>
        <property name="friends" ref="friends1"/>
    </bean>
    
    <bean id="friends1" class="org.codeart.springdemo.pojo.Friends">
        <property name="names">
            <list>
                <value>洛必达</value>
                <value>高斯</value>
                <value>伯努利</value>
                <value>欧拉</value>
            </list>
        </property>
    </bean>
</beans>

编写单元测试方法:

public class ApplicationContextTest {
    
    @Test
    public void testGetBean() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application-context.xml");
        User user1 = ctx.getBean("user1", User.class);
        Friends friends = user1.getFriends();
        friends.getNames().forEach(System.out::println);
    }

}

当然这种基于 xml 配置文件创建 Bean 的方式已经过时了。取而代之的是使用注解+配置类的方式,甚至有自动配置。

Spring的FactoryBean接口

首先 FactoryBean 是一个 Bean,但又不仅仅是一个 Bean,这样听起来矛盾,但为啥又这样说呢?其实在 Spring中,所有的 Bean 都是由 BeanFactory(也就是 IOC 容器)来进行管理的。但对 FactoryBean 而言,这个 FactoryBean 不是简单的 Bean,而是一个能生产或者修饰对象生成的工厂 Bean,它的实现与设计模式中的工厂方法模式和装饰器模式类似

为什么需要FactoryBean

在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在 XML 配置文件中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring 为此提供了一个org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。FactoryBean 接口对于 Spring 框架来说占用重要的地位,Spring 自身就提供了 70 多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 Bean 的细节,给上层应用带来了便利。

由于第三方库不能直接注册到 Spring 容器,于是可以实现 org.springframework.bean.factory.FactoryBean 接口,然后给出自己对象的实例化代码即可。

FactoryBean的使用特点

当用户使用容器本身时,可以使用转义字符 & 来得到 FactoryBean 本身,以区别通过 FactoryBean 产生的实例对象和 FactoryBean 对象本身。

在 BeanFactory 中通过如下代码定义了该转义字符:

StringFACTORY_BEAN_PREFIX = "&";

如果 myObject 对象是一个 FactoryBean 实例,则使用字符串 "&myObject" 得到的是 MyObject 类的对象,而不是 MyObject 生产出来的对象。

FactoryBean的简单使用

接下来演示一下如何使用 FactoryBean 接口,这一节我们使用注解+配置类的方式来配置上下文。

定义配置类:

@Configuration
@ComponentScan("com.example.factory_bean")
public class AppConfig {
    // ...
}

定义实体类:

@Data
public class IPhone {

    /**
     * 型号
     */
    private String model;

    /**
     * 电池容量
     */
    private Integer battery;

    /**
     * 出厂日期
     */
    private LocalDate productionDate;

}

定义工厂 Bean:

@Component("iPhoneFactoryBean")
public class IPhoneFactoryBean implements FactoryBean<IPhone> {

    @Override
    public IPhone getObject() throws Exception {
        return new IPhone();
    }

    @Override
    public Class<?> getObjectType() {
        return IPhone.class;
    }
}

编写单元测试:

public class FactoryBeanTest {

    @Test
    public void testFactoryBean() {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        IPhone iphone1 = (IPhone) ctx.getBean("iPhoneFactoryBean");
        // java.lang.ClassCastException
        IPhone iphone2 = (IPhone) ctx.getBean("&iPhoneFactoryBean");
        System.out.println(iphone1);
        System.out.println(iphone2);
    }
    
    // 修正为
    @Test
    public void testFactoryBean() {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        Object iphone1 = ctx.getBean("iPhoneFactoryBean");
        Object iphone2 = ctx.getBean("&iPhoneFactoryBean");
        System.out.println(iphone1.getClass());
        System.out.println(iphone2.getClass());
    }
}

打印结果:

image.png

FactoryBean接口源码分析

public interface FactoryBean<T> {

    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    /**
     * getObject 方法: 会返回该 FactoryBean 生产的对象实例,我们需要实现该方法,以给出自己的对象实例化逻辑
     * 这个方法也是 FactoryBean 的核心.
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * getObjectType 方法: 仅返回 getObject 方法所返回的对象类型,如果预先无法确定,返回 NULL,
     * 这个方法返回类型是在 IOC 容器中 getBean 所匹配的类型
     */
    @Nullable
    Class<?> getObjectType();

    // 该方法的结果用于表明工厂方法 getObject 所生产的对象是否要以单例形式存储在容器中如果以单例存在就返回 true,否则返回 false
    default boolean isSingleton() {
        return true;
    }
}

FactoryBean 表现的是一个工厂的职责,如果一个 BeanA 是实现 FactoryBean 接口,那么 A 就是变成了一个工厂,根据 A 的名称获取到的实际上是工厂调用 getObject 方法返回的对象,而不是对象本身。如果想获取工厂对象本身,需要在名称前面加上 & 符号。

  • getObject("name") 返回的是工厂中工厂方法生产的实例。
  • getObject("&name") 返回的是工厂本身实例。

使用场景

  • FactoryBean 的最为经典的使用场景,就是用来创建 AOP 代理对象,这个对象在 Spring 中就是ProxyFactoryBean

BeanFactory 与 FactoryBean区别

  • 它们两个都是工厂,但是 FactoryBean 本质还是一个 Bean,也归 BeanFactory 管理。
  • BeanFactory 是 Spring 容器的顶层接口,FactoryBean 更类似于用户自定义的工厂接口。

BeanFactory 和 ApplicationContext的区别

  • BeanFactory 是 Spring 容器的顶层接口,而 ApplicationContext 应用上下文类,它是 BeanFactory 的子接口,它是 Spring 中更高级的容器,提供了更多的功能。

    • 国际化
    • 访问资源
    • 载入多个上下文
    • 消息发送、响应机制
  • 两者的装载 Bean 的时机不同

BeanFactory 在系统启动的时候不会去实例化 Bean,只有从容器中拿 Bean 的时候才会去实例化(懒加载)。 优点:应用启动的时候占用的资源比较少,对资源的使用要求比较高的应用,比较有优势。

ApplicationContext 在启动的时候就把所有的 Bean 全部实例化。lazy-init=true 可以使 Bean 延时实例化 优点: 所有的 Bean 在启动的时候就加载,系统运行的速度快,还可以及时的发现系统中配置的问题。

Spring Framework的观察者模式

观察者模式与发布订阅模式异同

观察者模式它是用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应的作出反应。

在观察者模式中发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以应对多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

观察者模式的别名有发布-订阅(Publish/Subscribe)模式,我们来看一下观察者模式与发布订阅模式结构上的区别:

  • 在设计模式结构上,发布订阅模式继承自观察者模式,是观察者模式的一种实现的变体。
  • 在设计模式意图上,两者关注点不同,一个关心数据源,一个关心的是事件消息。

image.png

观察者模式里,只有两个角色:观察者 + 被观察者; 而发布订阅模式里,却不仅仅只有发布者和订阅者两个角色,还有一个管理并执行消息队列的“经纪人Broker”。

观察者和被观察者,是松耦合的关系。发布者和订阅者,则完全不存在耦合。

  • 观察者模式:数据源直接通知订阅者发生改变。
  • 发布订阅模式:数据源告诉第三方(事件通道)发生了改变,第三方再通知订阅者发生了改变。

Spring中的实现

Spring 基于观察者模式,实现了自身的事件机制也就是事件驱动模型,事件驱动模型通常也被理解成观察者或者发布/订阅模型。

Spring 事件模型提供如下几个角色:

  • ApplicationEvent
  • ApplicationListener
  • ApplicationEventPublisher
  • ApplicationEventMulticaster

ApplicationEvent

它是所有事件对象的父类。ApplicationEvent 继承自 JDK 内置的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过 source 得到事件源。

public abstract class ApplicationEvent extends EventObject {

   /** use serialVersionUID from Spring 1.2 for interoperability. */
   private static final long serialVersionUID = 7099057708183571937L;

   /** System time when the event happened. */
   private final long timestamp;

   /**
    * Create a new {@code ApplicationEvent}.
    * @param source the object on which the event initially occurred or with
    * which the event is associated (never {@code null})
    */
   public ApplicationEvent(Object source) {
      super(source);
      this.timestamp = System.currentTimeMillis();
   }


   /**
    * Return the system time in milliseconds when the event occurred.
    */
   public final long getTimestamp() {
      return this.timestamp;
   }

}

Spring 也为我们提供了很多内置事件:

  • ContextRefreshEvent:当 ApplicationContext 容器初始化完成或者被刷新的时候,就会发布该事件。
  • ContextStartedEvent:当 ApplicationContext 启动的时候发布事件.
  • ContextStoppedEvent:当 ApplicationContext 容器停止的时候发布事件.
  • RequestHandledEvent:只能用于 DispatcherServlet 的 web 应用,Spring 处理用户请求结束后,系统会触发该事件。

image.png

ApplicationListener

ApplicationListener (应用程序事件监听器)继承自 JDK 的 EventListener,所有的监听器都要实现这个接口,这个接口只有一个 onApplicationEvent 方法,该方法接受一个 ApplicationEvent 或其子类对象作为参数。

在方法体中,可以通过不同对 Event 类的判断来进行相应的处理。当事件触发时所有的监听器都会收到消息,如果你需要对监听器的接收顺序有要求,可以使用该接口的一个实现类 SmartApplicationListener,通过这个接口可以指定监听器接收事件的顺序。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

   /**
    * Handle an application event.
    * @param event the event to respond to
    */
   void onApplicationEvent(E event);

}

实现了 ApplicationListener 接口之后,需要实现方法 onApplicationEvent,在容器将所有的 Bean 都初始化完成之后,就会执行该方法。

ApplicationEventPublisher

事件的发布者,封装了事件发布功能方法接口,是 Applicationcontext 接口的超类。

事件机制的实现需要三个部分:事件源、事件、事件监听器。在上面介绍的 ApplicationEvent 就相当于事件,ApplicationListener 相当于事件监听器,这里的事件源说的就是 ApplicationEventPublisher

@FunctionalInterface
public interface ApplicationEventPublisher {

   default void publishEvent(ApplicationEvent event) {
      publishEvent((Object) event);
   }

   void publishEvent(Object event);

}

我们常用的 ApplicationContext 都继承了 AbstractApplicationContext,像我们平时常见ClassPathXmlApplicationContextXmlWebApplicationContext 也都是继承了它,AbstractApplicationContextApplicationContext 接口的抽象实现类,在该类中实现了publishEvent 方法。

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

在这个方法中,我们看到了一个 getApplicationEventMulticaster。这就要牵扯到另一个类ApplicationEventMulticaster

ApplicationEventMulticaster

用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 ApplicationContext 发布的事件 Event 广播给它的监听器列表。

public interface ApplicationEventMulticaster {

   /**
    * Add a listener to be notified of all events.
    * @param listener the listener to add
    */
   void addApplicationListener(ApplicationListener<?> listener);

   /**
    * Add a listener bean to be notified of all events.
    * @param listenerBeanName the name of the listener bean to add
    */
   void addApplicationListenerBean(String listenerBeanName);

   /**
    * Remove a listener from the notification list.
    * @param listener the listener to remove
    */
   void removeApplicationListener(ApplicationListener<?> listener);

   /**
    * Remove a listener bean from the notification list.
    * @param listenerBeanName the name of the listener bean to remove
    */
   void removeApplicationListenerBean(String listenerBeanName);

   /**
    * Remove all listeners registered with this multicaster.
    * <p>After a remove call, the multicaster will perform no action
    * on event notification until new listeners are registered.
    */
   void removeAllListeners();

   /**
    * Multicast the given application event to appropriate listeners.
    * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
    * if possible as it provides better support for generics-based events.
    * @param event the event to multicast
    */
   void multicastEvent(ApplicationEvent event);

   /**
    * Multicast the given application event to appropriate listeners.
    * <p>If the {@code eventType} is {@code null}, a default type is built
    * based on the {@code event} instance.
    * @param event the event to multicast
    * @param eventType the type of event (can be {@code null})
    * @since 4.2
    */
   void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);

}

AbstractApplicationcontext 中有一个 applicationEventMulticaster 的成员变量,提供了监听器Listener 的注册方法。

protected void registerListeners() {
   // Register statically specified listeners first.
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let post-processors apply to them!
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }

   // Publish early application events now that we finally have a multicaster...
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

事件监听简单示例

实现一个需求:当调用一个类的方法完成时,该类发布事件,事件监听器监听该类的事件并执行的自己的方法逻辑

假设这个类是 Request、发布的事件是 ReuqestEvent、事件监听者是 ReuqestListener。当调用 RequestdoRequest 方法时,发布事件。

定义 RequestEvent 类继承 ApplicationEvent 类:

public class RequestEvent extends ApplicationEvent {

    public RequestEvent(Object source) {
        super(source);
    }
    
}

定义 RequestPublisher 依赖 ApplicationContext 来发布事件:

@Component
public class RequestPublisher {
    
    @Autowired
    private ApplicationContext context;

    public void doRequest() {
        System.out.println("调用 RequestPublisher 发布了一个事件");
        context.publishEvent(new RequestEvent(this));
    }
}

定义 RequestListener 监听事件的发布:

@Component
public class RequestListener implements ApplicationListener<RequestEvent> {

    @Override
    public void onApplicationEvent(RequestEvent event) {
        System.out.println("收到了 RequestEvent 事件,执行本方法.");
    }
}

编写单元测试:

public class ListenerTest {

    @Test
    public void testPublishRequest() {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        RequestPublisher event = ctx.getBean(RequestPublisher.class);
        event.doRequest();
    }
}

打印结果:

image.png

事件机制工作流程

事件处理的执行流程:

image.png

监听器什么时候注册到 IOC 容器?

注册的开始逻辑是在 AbstractApplicationContext 类的 refresh 方法,该方法包含了整个 IOC 容器初始化所有方法。其中有一个 registerListeners 方法就是注册系统监听者(Spring 自带的)和自定义监听器的。

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         initMessageSource();

         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         onRefresh();

         // Check for listener beans and register them.
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         finishRefresh();
      } catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      } finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

registerListeners 方法的关键代码:其中的两个方法 addApplicationListeneraddApplicationListenerBean,从方法可以看出是添加监听者。

protected void registerListeners() {
   // Register statically specified listeners first.
   for (ApplicationListener<?> listener : getApplicationListeners()) {
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let post-processors apply to them!
   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }

   // Publish early application events now that we finally have a multicaster...
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

那么最后将监听者放到哪里了呢?就是 ApplicationEventMulticaster 接口的子类:

image.png

该接口主要两个职责,维护 ApplicationListener 相关类和发布事件。

实现在默认实现类 AbstractApplicationEventMulticaster,最后将 Listener 放到了内部类ListenerRetriever 两个 set 集合中:

image.png

Spring如何发布事件并通知监听者

publishEvent 方法:

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

multicastEvent 方法:

@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)) {
      // 如果executor不为null,则交给executor去调用监听器
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      } else {
         // 否则,使用当前主线程直接调用监听器
         invokeListener(listener, event);
      }
   }
}

invokeListeners 方法:

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

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.isTraceEnabled()) {
            logger.trace("Non-matching event type for listener: " + listener, ex);
         }
      }
      else {
         throw ex;
      }
   }
}

本篇文章若是对读者有启发,请多多点赞支持一下笔者,谢谢。分享知识,共同进步!