封面来源:碧蓝航线 愚者的天平 活动CG

Spring Application Event 官方文档:Standard and Custom Events

为了更好的阅读体验,请先将 SpringBoot 常用拓展点 作为前置阅读。

0. 前言

上周对 LinkedHashMap 的源码进行了剖析,那篇文章本应该在 4 月份就发布了,只是由于种种原因一拖再拖,甚至最终拖到了 7 月才正在发布,而这篇文章计划在剖析 LinkedHashMap 源码之后,预计 5 月份发布的,可前一篇的不断推迟,也导致本篇只能无奈地跟着顺延。但是没有关系,接下来我将开启“爆肝模式”,把前几个月落下的内容全部补齐。💪

还记得刚实习那会儿,自己的实力就算不是“非常菜”,但把“非常”两字去了也还是非常准确的。那时候自己对设计模式的了解仅限于理论,实际运用更是从来都没尝试过,而在自己第一次看到公司代码里基于 EventBus 实现的“发布-订阅”模式后,更是让我啧啧称奇。后来我了解到,这其实就是观察者模式的一种运用。

Spring 作为 Java 中的顶级明星框架,自然也实现了事件的“发布-订阅”模式(或者说事件监听机制),那就跟随本文,一起看看 Spring 的底层是如何实现模式的。

1. ResolvableType

在 Spring 的许多内部机制中,ResolvableType 被用来进行类型匹配和检查。在后续的源码分析中会看到 ResolvableType 的使用,因此有必要简单介绍下它的使用。

1.1 概述

ResolvableType 对 Java 中的 java.lang.reflect.Type 进行了封装,提供了获取目标 Type 的父类、接口和泛型参数的能力。

ResolvableType 能够从一个字段(Field)、一个方法参数、方法返回值类型或一个类(Class)中获取。ResolvableType 的大多数方法也都会返回一个 ResolvableType 实例,以便后续使用。

1.2 简单使用

有一个名为 MyMap 的类,它继承了 HashMap

1
2
3
4
static class MyMap extends HashMap<String, List<Integer>> {
    @Serial
    private static final long serialVersionUID = -9026643848761552207L;
}

如何获取继承的 HashMap 的泛型信息呢?

ResolvableType 针对这个场景提供了许多简单易用的 API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void testResolvableType() {
    ResolvableType myMapType = ResolvableType.forClass(MyMap.class);
    // 泛型参数在父类的 HashMap 中,因此先获取到父类的 ResolvableType
    ResolvableType hashMapType = myMapType.getSuperType();
    // 根据索引获取泛型信息 String
    ResolvableType firstGenericType = hashMapType.getGeneric(0);
    Class<?> firstGenericClazz = firstGenericType.resolve();
    assertThat(firstGenericClazz).isEqualTo(String.class);

    // 再获取第二个泛型信息 List<Integer>
    ResolvableType secondGenericType = hashMapType.getGeneric(1);
    ResolvableType secondFirstGenericType = secondGenericType.getGeneric(0);
    Class<?> secondFirstGenericClazz = secondFirstGenericType.resolve();
    assertThat(secondFirstGenericClazz).isEqualTo(Integer.class);
}

除了使用 forClass()静态工厂来构建 ResolvableType 实例外,还有许多其他构建方式:

  • forField()
  • forMethodReturnType()
  • forMethodParameter()
  • forConstructorParameter()

对于每种创建方式,ResolvableType 还提供了多种重载,以满足不同的使用场景。

大多数创建方式都能直观地看出其实际作用,但有一小部分并没有那么直观,本节将针对“没那么直观”的部分进行讲解。

1.3 forRawClass

forRawClass() 方法接收一个 Class 类型的参数,返回该 Class 的原始类(Raw Class)的 ResolvableType 对象。

看一个和 forClass() 的对比:

1
2
3
4
5
6
7
8
9
10
@Test
public void testForRawClass() {
    ResolvableType type = ResolvableType.forClass(List.class);
    // 包含泛型信息
    assertThat(type.toString()).isEqualTo("java.util.List<?>");

    type = ResolvableType.forRawClass(List.class);
    // 不包含泛型信息
    assertThat(type.toString()).isEqualTo("java.util.List");
}

1.4 forClass 的重载

forClass() 方法除了接收一个单一的 Class 对象外,还提供了一个重载:

1
ResolvableType forClass(Class<?> baseType, Class<?> implementationClass)

这个重载能够 返回具有给定实现类型(implementationClass)的基类(baseType)的 ResolvableType

这将用于描述类似多态的场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static class Foo<T> {
}

static class Bar extends Foo<String> {
}

@Test
public void testForClass() {
    ResolvableType type = ResolvableType.forClass(Bar.class);
    /*
     * 把当前 ResolvableType 转换成给定的 ResolvableType
     * Bar 是 Foo 的子类,将 Bar 转成 Foo
     */
    ResolvableType fooType = type.as(Foo.class);
    assertThat(fooType.toString()).contains("Foo<java.lang.String>");


    // 类似于 Foo<String> foo = new Bar();
    fooType = ResolvableType.forClass(Foo.class, Bar.class);
    assertThat(fooType.toString()).contains("Foo<java.lang.String>");
}

1.5 forConstructorParameter 的重载

forConstructorParameter() 方法用于获取指定构造器参数的 ResolvableType,和 forClass() 方法类似,它也提供了一个的重载:

1
ResolvableType forConstructorParameter(Constructor<?> constructor, int parameterIndex, Class<?> implementationClass)

这个重载解决的场景也和 forClass() 的重载类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static class GenericClass<T> {
    public GenericClass(T value) {
    }
}

static class IntegerGenericClass extends GenericClass<Integer> {
    public IntegerGenericClass(Integer value) {
        super(value);
    }
}

@Test
public void testForConstructorParameter() {
    ResolvableType type = ResolvableType.forConstructorParameter(GenericClass.class.getConstructors()[0], 0);
    assertThat(type.toString()).isEqualTo("?");
    type = ResolvableType.forConstructorParameter(GenericClass.class.getConstructors()[0], 0, IntegerGenericClass.class);
    assertThat(type.toString()).isEqualTo("java.lang.Integer");
}

1.6 forField 的重载

使用 forField() 方法能够获取 Field 对象对应的 ResolvableType 对象,和 forClassforConstructorParameter 类似,forField() 提供了处理泛型变量的重载:

1
ResolvableType forField(Field field, Class<?> implementationClass)

使用方式也类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static class BaseClass<T> {
    protected T value;
}

static class StringClass extends BaseClass<String> {
}

@Test
@SneakyThrows
public void testForField_1() {
    Field field = BaseClass.class.getDeclaredField("value");
    ResolvableType type = ResolvableType.forField(field);
    assertThat(type.toString()).isEqualTo("?");

    type = ResolvableType.forField(field, StringClass.class);
    assertThat(type.toString()).isEqualTo("java.lang.String");
}

对于拥有多层嵌套的泛型参数,forField() 还支持传入 nestingLevel(嵌套等级)来精准获取嵌套泛型的 ResolvableType

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static class NestedFieldClass {
    private List<List<Integer>> list;
}

@Test
@SneakyThrows
public void testForField_2() {
    Field field = NestedFieldClass.class.getDeclaredField("list");
    ResolvableType type = ResolvableType.forField(field);
    assertThat(type.toString()).isEqualTo("java.util.List<java.util.List<java.lang.Integer>>");

    // 1 表示外层,2 及其以后才是嵌套泛型
    type = ResolvableType.forField(field, 1);
    assertThat(type.toString()).isEqualTo("java.util.List<java.util.List<java.lang.Integer>>");

    type = ResolvableType.forField(field, 2);
    assertThat(type.toString()).isEqualTo("java.util.List<java.lang.Integer>");

    type = ResolvableType.forField(field, 3);
    assertThat(type.toString()).isEqualTo("java.lang.Integer");
}

需要注意的是,传入的参数名叫 nestingLevel,这里使用的是 Level,而不是 Index,因此它的起始值是从 1 开始,而不是从 0 开始的。

1.7 forType 的重载

先简单介绍下 Java 中的 Type 接口的体系:

classDiagram

class Type {
    <<interface>>
    getTypeName()
}

class Class~T~

class GenericArrayType {
    <<interface>>
    Type getGenericComponentType()
}

class ParameterizedType {
    <<interface>>
    Type[] getActualTypeArguments()
    Type getRawType()
    Type getOwnerType()
}

class TypeVariable~D extends GenericDeclaration~{
    <<interface>>
    Type[] getBounds()
    D getGenericDeclaration()
    String getName()
    AnnotatedType[] getAnnotatedBounds()
}

class WildcardType {
    <<interface>>
    Type[] getUpperBounds()
    Type[] getLowerBounds()
}

Type <|.. Class~T~
Type <|-- ParameterizedType 
Type <|-- GenericArrayType
Type <|-- TypeVariable~D extends GenericDeclaration~
Type <|-- WildcardType
  • Class 就很熟悉了,用于表示类和接口类型
  • ParameterizedType 用于表示参数化类型,比如 List<String>
  • GenericArrayType 用于表示泛型数组类型,比如 T[]
  • TypeVariable 用于表示类型变量,比如 T
  • WildcardType 用于表示通配符类型,比如 ? extends Number

一份简单的“食用”示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
static class Sample<T> {
    List<String> list;
    T[] array;
    List<? extends Number> wildcardList;
}

@Test
@SneakyThrows
public void testTypeSystem() {
    // 获取类的类型
    Class<?> clazz = Class.forName("java.util.List");
    assertThat(clazz.toString()).isEqualTo("interface java.util.List");

    // 获取参数化类型
    Field field = Sample.class.getDeclaredField("list");
    Type genericType = field.getGenericType();
    if (genericType instanceof ParameterizedType parameterizedType) {
        // 原始类型
        assertThat(parameterizedType.getRawType().toString())
                .isEqualTo("interface java.util.List");
        // 实际类型参数
        assertThat(parameterizedType.getActualTypeArguments())
                .extracting(Object::toString)
                .containsOnly("class java.lang.String");
    }

    // 获取泛型数组类型
    Field arrayField = Sample.class.getDeclaredField("array");
    Type arrayType = arrayField.getGenericType();
    if (arrayType instanceof GenericArrayType genericArrayType) {
        assertThat(genericArrayType.getGenericComponentType().toString())
                .isEqualTo("T");
    }

    // 获取类型变量
    TypeVariable<Class<Sample>>[] typeParameters = Sample.class.getTypeParameters();
    assertThat(typeParameters.length).isEqualTo(1);
    TypeVariable<Class<Sample>> typeParam = typeParameters[0];
    assertThat(typeParam.getName()).isEqualTo("T");
    // 获取类型变量的上界
    assertThat(typeParam.getBounds())
            .singleElement()
            .extracting(Objects::toString)
            .isEqualTo("class java.lang.Object");

    // 获取通配符类型
    Field wildcardField = Sample.class.getDeclaredField("wildcardList");
    Type wildcardType = wildcardField.getGenericType();
    if (wildcardType instanceof ParameterizedType parameterizedType) {
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        assertThat(actualTypeArguments.length).isEqualTo(1);
        Type typeArg = actualTypeArguments[0];
        if (typeArg instanceof WildcardType wildcard) {
            assertThat(wildcard.getUpperBounds())
                    .singleElement()
                    .extracting(Objects::toString)
                    .isEqualTo("class java.lang.Number");

            assertThat(wildcard.getLowerBounds()).isEmpty();
        }
    }
}

言归正传,forType() 就是用于获取 Type 实例的 ResolvableTypeResolvableTypeforType() 提供了三种重载,还是用一份代码搞定“食用”示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static class Outer<T> {
    public T genericMethod() {
        return null;
    }
}

@Test
@SneakyThrows
public void testForType() {
    ResolvableType type = ResolvableType.forType(Bar.class);
    assertThat(type.toString())
            .contains("Bar")
            .doesNotContain("Foo");

    ParameterizedTypeReference<List<String>> typeReference = new ParameterizedTypeReference<>() {
    };
    type = ResolvableType.forType(typeReference);
    assertThat(type.toString()).isEqualTo("java.util.List<java.lang.String>");

    Method method = Outer.class.getMethod("genericMethod");
    type = ResolvableType.forMethodReturnType(method);
    assertThat(type.toString()).isEqualTo("?");
    ResolvableType genericClassType = ResolvableType.forClassWithGenerics(Outer.class, String.class);
    type = ResolvableType.forType(method.getGenericReturnType(), genericClassType);
    assertThat(type.toString()).isEqualTo("java.lang.String");
}

1.8 forInstance

forInstance() 能够直接获取一个实例对应的 ResolvableType

由于 Java 的泛型擦除,直接使用该方法可能无法获取到实际的泛型参数类型,此时可以要求实例所在的类实现 ResolvableTypeProvider 接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static class MyGenericClass<T> {
}

static class MyGenericClass2<T> implements ResolvableTypeProvider {

    private final T payload;

    public MyGenericClass2(T payload) {
        this.payload = payload;
    }

    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(MyGenericClass2.class, payload.getClass());
    }
}

@Test
public void testForInstance() {
    MyGenericClass<Integer> obj = new MyGenericClass<>();
    ResolvableType type = ResolvableType.forInstance(obj);
    // 拿不到实际的泛型
    assertThat(type.toString()).contains("MyGenericClass<?>");

    MyGenericClass2<String> object = new MyGenericClass2<>("payload");
    type = ResolvableType.forInstance(object);
    // 实现 ResolvableTypeProvider 后就拿得到了
    assertThat(type.toString()).contains("MyGenericClass2<java.lang.String>");
}

1.9 getNested 的重载

ResolvableType 中的成员方法都比较简单,基本都能见名知义,就不一一介绍每个方法的使用方式了。

在这些成员方法中,有个名为 getNested() 的方法,显然这是用于获取嵌套泛型的 ResolvableType 信息。

除了只接收一个 nestingLevel 参数外,它还有一个重载:

1
ResolvableType getNested(int nestingLevel, @Nullable Map<Integer, Integer> typeIndexesPerLevel)

typeIndexesPerLevel 参数类型是 Map,对其进行直译可以理解为“每层的类型索引”。

还是用个用例来理解它的使用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void testGetNested() {
    ParameterizedTypeReference<List<Map<String, List<Integer>>>> typeReference = new ParameterizedTypeReference<>() {
    };
    ResolvableType type = ResolvableType.forType(typeReference);
    ResolvableType nested = type.getNested(1);
    // 第一层就是最外面的
    assertThat(nested.toString()).isEqualTo("java.util.List<java.util.Map<java.lang.String, java.util.List<java.lang.Integer>>>");

    nested = type.getNested(2);
    assertThat(nested.toString()).isEqualTo("java.util.Map<java.lang.String, java.util.List<java.lang.Integer>>");

    /*
     * nestingLevel: 第三层嵌套
     * 2 -> 0: 第 2 层嵌套取 index = 0 的泛型,即: Map<String, List<Integer>>>
     * 3 -> 1: 第 3 层嵌套取 index = 1 的泛型,即: List<Integer>
     */
    nested = type.getNested(3, Map.of(2, 0, 3, 1));
    assertThat(nested.toString()).isEqualTo("java.util.List<java.lang.Integer>");
}

这两个参数有些细节需要注意:

  • nestingLevel 重点在 Level,从 1 开始
  • typeIndexesPerLevel 类型是 Map,其 key 是指 Level,要从 1 开始,但 value 是指 Index,此时要从 0 开始

Level 和 Index 的区别有点坑,使用时应当特别注意。😣

1.10 hasUnresolvableGenerics

hasUnresolvableGenerics() 用于检查当前 ResolvableType 中是否包含无法解析的泛型参数。

1
2
3
4
5
6
7
8
@Test
public void testHasUnresolvableGenerics() {
    ResolvableType type = ResolvableType.forClassWithGenerics(List.class, Integer.class);
    assertThat(type.hasUnresolvableGenerics()).isFalse();

    type = ResolvableType.forClass(List.class);
    assertThat(type.hasUnresolvableGenerics()).isTrue();
}

2. 简单的示例

Spring 内部提供了多种发布事件与监听事件的方式,并且随着 Spring 的不断迭代,使用方式也越来越简单。

不必纠结茴字有几种写法,直接聚焦于最简单的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@SpringBootApplication
public class SimpleSpringEventListenerTest {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SimpleSpringEventListenerTest.class, args);
        context.publishEvent(new UserRegisterEvent("成功注册用户: mofan"));
        context.close();
    }

    @Slf4j
    @Component
    private static class UserRegisterEventListener {
        @EventListener
        public void doEvent(UserRegisterEvent event) {
            log.info("监听到用户注册事件: {}", event.info());
        }
    }

    private record UserRegisterEvent(String info) {
    }
}

运行 main() 方法后,控制台打印出:

监听到用户注册事件: 成功注册用户: mofan

这个 Demo 可以说是非常简单了,简单得连整个逻辑都是在一个类中完成的。

言归正传,Spring 底层究竟是怎么实现这种事件的发布与监听机制呢?

3. 猜想与假设

从上述 Demo 的执行过程可以看到,执行 publishEvent() 方法发布事件后,会立即执行 UserRegisterEventListener 中的 doEvent() 方法。

UserRegisterEventListener 类被 @Component 注解修饰,会在 SpringApplication.run() 方法执行后添加到 Spring 容器中。

Spring 实现的事件监听机制其实就是设计模式中 观察者模式 的应用,根据对观察者模式的理解,不妨大胆猜测:当调用 publishEvent() 方法发布事件后,会遍历当前程序中所有的监听器,如果存在对应事件的监听器,那么就会调用监听器中的方法,完成事件监听。

如果要验证这个猜想,可以从以下几个方面出发:

  • 监听器是怎么注册的,或者说 @EventListener 注解是怎么解析的
  • 调用 publishEvent() 方法后,是怎么触发监听器的

4. 注册监听器

事件监听器的注册涉及到 EventListenerMethodProcessor,先看它的定义:

1
2
3
4
public class EventListenerMethodProcessor
       implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
    // --snip--
}

实现了三个经典的拓展点,关于这些拓展点的使用方式、加载时机、执行时机可以参考 SpringBoot 常用拓展点,这里不再赘述。

EventListenerMethodProcessor 的加载与执行和解析 @Autowired 注解的 AutowiredAnnotationBeanPostProcessor 非常相似:

flowchart TD
1("...")
subgraph 2 ["createApplicationContext()"]
2.1("1. 注册 EventListenerMethodProcessor 的 BeanDefinition"):::orange-red-filling
end
3("prepareContext()")
subgraph 4 ["refreshContext()"]
subgraph 4.1 ["AbstractApplicationContext#invokeBeanFactoryPostProcessors"]
4.1.1("2. 调用 EventListenerMethodProcessor#postProcessBeanFactory() 获取 EventListenerFactory"):::orange-red-filling
end
subgraph 4.2 ["finishBeanFactoryInitialization()"]
4.2.1("3. 调用 EventListenerMethodProcessor#afterSingletonsInstantiated() 注册监听器"):::orange-red-filling
end
end
5("...")

1 --> 2 --> 3 --> 4 --> 5
4.1 --> 4.2
classDef orange-red-filling fill:#f96;

EventListenerMethodProcessor 的加载与执行分为 3 步:

  1. 在调用 createApplicationContext() 创建 ApplicationContext 时,注册 EventListenerMethodProcessorBeanDefinition
  2. EventListenerMethodProcessor 实现了 BeanFactoryPostProcessor 接口,因此在 refresh 过程中会调用 postProcessBeanFactory() 方法,获取 EventListenerFactory 用于后续创建事件监听器
  3. EventListenerMethodProcessor 也实现了 SmartInitializingSingleton 接口,之后还会调用 afterSingletonsInstantiated() 方法用于创建事件监听器

4.1 注册处理器

1
2
3
protected ConfigurableApplicationContext createApplicationContext() {
    return this.applicationContextFactory.create(this.webApplicationType);
}

未设置过 applicationContextFactory 的情况下,将使用默认值:

1
2
3
4
5
// class SpringApplication
private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;

// interface ApplicationContextFactory
ApplicationContextFactory DEFAULT = new DefaultApplicationContextFactory();

内部创建按需 ConfigurableApplicationContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 创建方法
@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
    try {
        return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create,
                                      this::createDefaultApplicationContext);
    }
    catch (Exception ex) {
        throw new IllegalStateException("Unable create a default ApplicationContext instance, "
                                        + "you may need a custom ApplicationContextFactory", ex);
    }
}

// 默认值
private ConfigurableApplicationContext createDefaultApplicationContext() {
    if (!AotDetector.useGeneratedArtifacts()) {
        // 程序通常会执行到这
        return new AnnotationConfigApplicationContext();
    }
    return new GenericApplicationContext();
}

private <T> T getFromSpringFactories(WebApplicationType webApplicationType,
                                     BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) {
    // 循环从 META-INF/spring.factories 加载的 ApplicationContextFactory 实现类
    for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,
                                                                                   getClass().getClassLoader())) {
        // 调用它们的 create() 方法创建
        T result = action.apply(candidate, webApplicationType);
        if (result != null) {
            return result;
        }
    }
    // 如果返回的 result 都是 null,给个默认值
    return (defaultResult != null) ? defaultResult.get() : null;
}

META-INF/spring.factories 加载 ApplicationContextFactory 后,调用重写的 create() 方法返回 result,如果 result != null,就直接返回。

如果能够加载到 ApplicationContextFactory,并且 create() 方法返回的 result 也不是 null,加载的 ApplicationContextFactory 通常是 ServletWebServerApplicationContextFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ServletWebServerApplicationContextFactory implements ApplicationContextFactory {

    // --snip--

    @Override
    public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
        return (webApplicationType != WebApplicationType.SERVLET) ? null : createContext();
    }

    private ConfigurableApplicationContext createContext() {
        if (!AotDetector.useGeneratedArtifacts()) {
            // 程序通常会执行到这
            return new AnnotationConfigServletWebServerApplicationContext();
        }
        return new ServletWebServerApplicationContext();
    }

}

一般来说,调用该实现类的 create() 会返回一个 AnnotationConfigServletWebServerApplicationContext 实例。

如果调用加载的 ApplicationContextFactorycreate() 方法返回的 result 都是 null,最后则会执行 defaultResult 逻辑,给一个默认值:

1
2
3
4
5
6
7
private ConfigurableApplicationContext createDefaultApplicationContext() {
    if (!AotDetector.useGeneratedArtifacts()) {
        // 程序通常会执行到这
        return new AnnotationConfigApplicationContext();
    }
    return new GenericApplicationContext();
}

简单总结下创建 ConfigurableApplicationContext 的过程:

flowchart TB
a(["开始"])
b("从 META-INF/spring.factories 中加载若干个 ApplicationContextFactory")
c("遍历每个加载的 Factory")
d("调用 create() 方法创建")
e{"创建结果是 null"}
f{"是否处理完加载的<br/> Factory"}
g("使用默认方式创建")
h("返回创建的对象")
z(["结束"])

a --> b --> c --> d --> e
e --> |是|f
e --> |否|h
f --> |是|g
f --> |否|c
g --> h --> z

根据前文的描述,这里创建的 ConfigurableApplicationContext 通常有两种:

  1. AnnotationConfigServletWebServerApplicationContext
  2. AnnotationConfigApplicationContext

但无论是哪一种,在调用它们自己的构造函数时,都会再去创建 AnnotatedBeanDefinitionReader 实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public AnnotationConfigServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
    super(beanFactory);
    // here
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

public AnnotationConfigApplicationContext() {
    StartupStep createAnnotatedBeanDefReader = getApplicationStartup().start("spring.context.annotated-bean-reader.create");
    // here
    this.reader = new AnnotatedBeanDefinitionReader(this);
    createAnnotatedBeanDefReader.end();
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

而在构造 AnnotatedBeanDefinitionReader 时就会去注册 EventListenerMethodProcessorBeanDefinition

1
2
3
4
5
6
7
8
9
10
11
12
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this(registry, getOrCreateEnvironment(registry));
}

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    // 加载
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

注册该处理器的逻辑由 AnnotationConfigUtils.registerAnnotationConfigProcessors() 方法完成:

1
2
3
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
       BeanDefinitionRegistry registry, @Nullable Object source) {

    // --snip--

    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    // 注册 ConfigurationClassPostProcessor,可用于处理 @Configuration

    // 注册 AutowiredAnnotationBeanPostProcessor,可用于处理 @Autowired、@Value

    // 注册 CommonAnnotationBeanPostProcessor,可用于处理 @Resource、@PostConstruct

    // 注册 PersistenceAnnotationBeanPostProcessor,对 JPA 的支持

    // 注册 EventListenerMethodProcessor
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
       RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
       def.setSource(source);
       beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    // 注册 DefaultEventListenerFactory
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
       RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
       def.setSource(source);
       beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
}

在最后两步里,先是注册了 EventListenerMethodProcessor,最后还注册了 DefaultEventListenerFactory。这个 DefaultEventListenerFactory 也有大用处,后面会说到。

到此,EventListenerMethodProcessorBeanDefinition 已经成功注册了,如果后续要获取对应的 Bean,调用下 BeanFactory 中的 getBean() 方法即可。

4.2 postProcessBeanFactory

随着程序的执行,来到 refresh 阶段。

EventListenerMethodProcessor 实现了 BeanFactoryPostProcessor 接口,因此在调用 AbstractApplicationContext#invokeBeanFactoryPostProcessors() 方法时就会执行 EventListenerMethodProcessor 重写的 postProcessBeanFactory() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    this.beanFactory = beanFactory;
    this.originalEvaluationContext.setBeanResolver(new BeanFactoryResolver(this.beanFactory));

    // 获取 EventListenerFactory 类型的 Bean
    Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
    List<EventListenerFactory> factories = new ArrayList<>(beans.values());
    // 排个序
    AnnotationAwareOrderComparator.sort(factories);
    // 设置成员变量
    this.eventListenerFactories = factories;
}

方法内部逻辑很简单,重点是获取了容器中所有 EventListenerFactory 类型的 Bean。

上一节中介绍注册 EventListenerMethodProcessor 时,还说到会注册 DefaultEventListenerFactory,而它就是 EventListenerFactory 的默认实现。

Call Back 了,属于是。😆

EventListenerFactory 有什么用呢?

从名字就能看出,这玩意是用来创建事件监听器(EventListener)的,那它会在什么时候创建呢?

4.3 afterSingletonsInstantiated

refresh 阶段干的事有很多,SmartInitializingSingleton 接口的执行阶段也是在这,该接口被执行时,表明 容器中所有的单例 Bean 已经都被实例化 完了。

EventListenerMethodProcessor 好巧不巧也实现了 SmartInitializingSingleton,其实也很好理解,只有单例 Bean 都实例化了,才能解析 @EventListener 注解,不然漏了咋办?

重写的 afterSingletonsInstantiated() 方法不算很长,但条件判断和异常处理比较多,代码格式不是很好,就不贴代码了,直接概括下主要逻辑:

  1. 通过 beanFactory.getBeanNamesForType(Object.class) 获取 Spring 容器中所有的 Bean 的 name;
  2. 根据 name,获取 Bean 的实际类型 type(就这步导致条件判断和异常处理比较多);
  3. 最后根据 Bean 的 name、type 获取内部所有事件监听器。

重点在第三步,由 processBean() 方法完成,这个方法的格式也不太行,依旧概括下主要逻辑:

  1. 获取类中所有被 @EventListener 注解标记的方法;

    1
    2
    3
    4
    Map<Method, EventListener> annotatedMethods = null;
    annotatedMethods = MethodIntrospector.selectMethods(targetType,
                            (MethodIntrospector.MetadataLookup<EventListener>) method ->
                                    AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
  2. 遍历这些方法,把它们包装成 ApplicationListener 对象添加到 ConfigurableApplicationContext 中。

关注下包装成 ApplicationListener 的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ConfigurableApplicationContext context = this.applicationContext;
List<EventListenerFactory> factories = this.eventListenerFactories;
// 遍历所有被 @EventListener 注解标记的方法
for (Method method : annotatedMethods.keySet()) {
    // 遍历 EventListenerFactory
    for (EventListenerFactory factory : factories) {
        // 判断是否执行对应的方法
        if (factory.supportsMethod(method)) {
            // 处理被代理的情况,找到正在执行的方法
            Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
            // 包装成 ApplicationListener
            ApplicationListener<?> applicationListener =
                factory.createApplicationListener(beanName, targetType, methodToUse);
            // 按需初始化,DefaultEventListenerFactory 的包装结果总是满足
            if (applicationListener instanceof ApplicationListenerMethodAdapter alma) {
                alma.init(context, this.evaluator);
            }
            // 添加到 ConfigurableApplicationContext
            context.addApplicationListener(applicationListener);
            // 一个监听器方法最多只能被一个 Factory 包装
            break;
        }
    }
}

遍历 factories 时,可以拿到默认实现 DefaultEventListenerFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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;
    }


    @Override
    public boolean supportsMethod(Method method) {
        return true;
    }

    @Override
    public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
        return new ApplicationListenerMethodAdapter(beanName, type, method);
    }

}

内部逻辑比较简单,supportsMethod() 方法总是返回 truecreateApplicationListener() 返回的 ApplicationListenerMethodAdapter 实例(满足按需初始化,会调用 init() 方法)。

ApplicationListenerMethodAdapter 也比较重要,先混个眼熟。😁

当然,实际工作环境中拿到的 factories 可能会有很多种,但在本文的例子中,@EventListener 标记的方法就是用 DefaultEventListenerFactory 包装的。

ConfigurableApplicationContext#addApplicationListener()

简单说下添加事件监听器的逻辑,调用后会来到 AbstractApplicationContext#addApplicationListener() 方法中:

1
2
3
4
5
6
7
8
@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);
}

在这里会向 applicationEventMulticaster 中添加监听器。它又是怎么来的呢?

其值变化逻辑分布在两处:

  1. initApplicationEventMulticaster()
  2. doClose()

显然 applicationEventMulticaster 是在 initApplicationEventMulticaster() 方法中被设置的(这个方法会在 refresh 阶段执行):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // 当前容器中是否包含名为 applicationEventMulticaster 的 Bean(不包括父容器)
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        // 如果有,那就拿到它,并设置 applicationEventMulticaster
       this.applicationEventMulticaster =
             beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
       if (logger.isTraceEnabled()) {
          logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
       }
    }
    else {
        // 如果没有,就创建一个并设置 applicationEventMulticaster
       this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        // 顺便在容器中注册一个新 Bean
       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 通常是 SimpleApplicationEventMulticaster 实例。

它内部的 addApplicationListener() 的逻辑又是怎样的呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();

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

简单来说就是向 defaultRetriever 中添加监听器。

无论是 AbstractApplicationContext 中的 applicationEventMulticaster,还是 SimpleApplicationEventMulticaster 中的 defaultRetriever,也都得混个眼熟,后面介绍事件的发布和监听是都会用到。

到此,事件监听器的注册就算告一段落了,但这仅仅是一个开始,上述所有逻辑都是在调用的 SpringApplication.run() 方法中完成的,相当于只做了准备工作,完全不涉及到事件的发布与监听。各种复杂的逻辑由一个 run() 方法就搞定了,不得不再次感叹 SpringBoot 极致的封装性。

5. 发布事件

事件的发布由 ApplicationEventPublisher 接口完成:

1
2
3
4
5
6
7
8
@FunctionalInterface
public interface ApplicationEventPublisher {
    default void publishEvent(ApplicationEvent event) {
        publishEvent((Object) event);
    }
    
    void publishEvent(Object event);
}

ApplicationContext 接口也是它的子接口,因此可以用 ApplicationContext 及其子类调用 publishEvent() 方法完成事件的发布。

调用 publishEvent() 方法后会进入“老熟人” AbstractApplicationContext 中:

1
2
3
public void publishEvent(Object event) {
    publishEvent(event, null);
}

它又调用了内部的一个重载:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
protected void publishEvent(Object event, @Nullable ResolvableType typeHint) {
    Assert.notNull(event, "Event must not be null");
    ResolvableType eventType = null;

    // Decorate event as an ApplicationEvent if necessary
    ApplicationEvent applicationEvent;
    // 判断发布的事件是否是 ApplicationEvent 类型
    if (event instanceof ApplicationEvent applEvent) {
        applicationEvent = applEvent;
        eventType = typeHint;
    }
    else {
        ResolvableType payloadType = null;
        if (typeHint != null && ApplicationEvent.class.isAssignableFrom(typeHint.toClass())) {
            eventType = typeHint;
        }
        else {
            payloadType = typeHint;
        }
        // 如果不是,包装成 PayloadApplicationEvent
        // 示例代码会走到这,并且 payloadType 依旧是 null
        applicationEvent = new PayloadApplicationEvent<>(this, event, payloadType);
    }

    // Determine event type only once (for multicast and parent publish)
    if (eventType == null) {
        // 获取事件类型,类型由 ResolvableType 实例表示
        eventType = ResolvableType.forInstance(applicationEvent);
        if (typeHint == null) {
            typeHint = eventType;
        }
    }

    // Multicast right now if possible - or lazily once the multicaster is initialized
    if (this.earlyApplicationEvents != null) {
        // 启动阶段发布的事件
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else if (this.applicationEventMulticaster != null) {
        // 使用 applicationEventMulticaster 广播事件
        // 示例代码会走到这
        this.applicationEventMulticaster.multicastEvent(applicationEvent, eventType);
    }

    // Publish event via parent context as well...
    // 事件还支持父子容器,子容器发布的事件,父容器可以监听到
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext abstractApplicationContext) {
            abstractApplicationContext.publishEvent(event, typeHint);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

根据最初的示例代码,发布的事件类型是 UserRegisterEvent

按照 publishEvent() 方法的逻辑,UserRegisterEvent 实例会被包装成 PayloadApplicationEvent,事件类型 eventType 就是包装成的 PayloadApplicationEvent 实例对应的 ResolvableType,最后的发布事件会使用 applicationEventMulticaster 对该事件进行广播。

如果继续深入 applicationEventMulticaster.multicastEvent() 方法就会进入事件监听阶段,其实事件发布与监听是一个连贯的逻辑,本文将其分开意在让读者更便于理解。

6. 监听事件

前文中已经分析过 applicationEventMulticaster 其实是 SimpleApplicationEventMulticaster 实例,那么调用 multicastEvent() 方法就会进入该类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
    // 再次拿到事件类型
    ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));
    // 获取一个线程池
    Executor executor = getTaskExecutor();
    // 遍历监听器
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        // 如果存在线程池,并且监听器支持异步执行
        if (executor != null && listener.supportsAsyncExecution()) {
            // 异步监听
            try {
                executor.execute(() -> invokeListener(listener, event));
            }
            catch (RejectedExecutionException ex) {
                // Probably on shutdown -> invoke listener locally instead
                invokeListener(listener, event);
            }
        }
        else {
            // 同步监听
            invokeListener(listener, event);
        }
    }
}

根据这部分源码可知,监听器的执行还支持异步,实际使用时在监听器方法上标记 @Async 注解即可轻松实现,这里不再展开。

主要逻辑由两个:

  1. 调用 getApplicationListeners() 获取事件监听器
  2. 调用 invokeListener() 执行监听器

6.1 获取事件监听器

getApplicationListeners() 方法主要干两件事:

  1. 尝试从缓存中获取事件监听器,如果获取到,直接返回;
  2. 没获取到,执行 retrieveApplicationListeners() 检索监听器并放到缓存里。

不纠结缓存的实现,直接进入 retrieveApplicationListeners()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
    ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever 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;
    // 从 defaultRetriever 中获取监听器
    synchronized (this.defaultRetriever) {
        // 示例中的监听器就在这里面
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        // 以 Bean 形式存在的监听器
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }

    // Add programmatically registered listeners, including ones coming
    // from ApplicationListenerDetector (singleton beans and inner beans).
    for (ApplicationListener<?> listener : listeners) {
        // 判断监听器是否支持当前事件
        if (supportsEvent(listener, eventType, sourceType)) {
            // 添加到缓存
            if (retriever != null) {
                filteredListeners.add(listener);
            }
            // 添加到结果集
            allListeners.add(listener);
        }
    }
    
    // --snip--
    
    return allListeners;
}

逻辑比较多,只截取重点。

已知的是 listeners 中存在示例中的监听器,接着需要通过 supportsEvent() 方法来过滤:

1
2
3
4
5
6
7
protected boolean supportsEvent(
       ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {

    GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener gal ? gal :
          new GenericApplicationListenerAdapter(listener));
    return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

在判断的时候会包装成 GenericApplicationListener 进行判断。

回顾下前文中介绍了监听器方法会被包装成 ApplicationListenerMethodAdapter

1
2
3
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
    // --snip--
}

它刚好是 GenericApplicationListener 的子类。

就看这类名,可以断定出 Spring 能够支持带泛型的事件。

接下里会调用 supportsEventType()supportsSourceType() 判断监听器是否支持当前发布的事件。

supportsSourceType() 总是返回 true,没啥好说的:

1
2
3
4
@Override
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
    return true;
}

supportsEventType() 方法中会使用 declaredEventTypes 成员变量,它在构造函数中通过调用 resolveDeclaredEventTypes() 进行初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private static List<ResolvableType> resolveDeclaredEventTypes(Method method, @Nullable EventListener ann) {
    // 获取方法参数个数
    int count = (KotlinDetector.isSuspendingFunction(method) ? method.getParameterCount() - 1 : method.getParameterCount());
    // 参数个数不能大于 1
    if (count > 1) {
        throw new IllegalStateException(
            "Maximum one parameter is allowed for event listener method: " + method);
    }

    if (ann != null) {
        // 如果注解的 classes 属性有值
        Class<?>[] classes = ann.classes();
        if (classes.length > 0) {
            List<ResolvableType> types = new ArrayList<>(classes.length);
            for (Class<?> eventType : classes) {
                // 将 classes 转换成 ResolvableType 后返回
                types.add(ResolvableType.forClass(eventType));
            }
            // 也就是说,如果指定了 classes,会忽略监听方法的参数
            // classes 的优先级更高
            return types;
        }
    }

    // classes 没值,方法参数个数也为 0
    if (count == 0) {
        throw new IllegalStateException(
            "Event parameter is mandatory for event listener method: " + method);
    }
    // 否则取第一个参数的 ResolvableType
    return Collections.singletonList(ResolvableType.forMethodParameter(method, 0));
}

declaredEventTypes 表示当前监听器支持哪些类型的事件。

回到 supportsEventType() 方法中,但在阅读源码前别忘记示例中的事件类型已经被包装成 PayloadApplicationEvent<UserRegisterEvent>,而不是原始类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// eventType --> PayloadApplicationEvent<UserRegisterEvent>
@Override
public boolean supportsEventType(ResolvableType eventType) {
    // 遍历监听器支持的事件类型,示例中的是 UserRegisterEvent
    for (ResolvableType declaredEventType : this.declaredEventTypes) {
        // 判断事件类型中是否有无法解析的泛型参数
        if (eventType.hasUnresolvableGenerics() ?
            declaredEventType.toClass().isAssignableFrom(eventType.toClass()) :
            // 会走到这
            // 判断 UserRegisterEvent 与 PayloadApplicationEvent<UserRegisterEvent>
            // 显然不满足
            declaredEventType.isAssignableFrom(eventType)) {
            return true;
        }
        if (PayloadApplicationEvent.class.isAssignableFrom(eventType.toClass())) {
            // 是否存在无法解析的泛型参数
            if (eventType.hasUnresolvableGenerics()) {
                return true;
            }
            // 获取 eventType 的泛型参数信息,相当于拿到 UserRegisterEvent
            ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
            // 那这个判断肯定满足了
            if (declaredEventType.isAssignableFrom(payloadType)) {
                return true;
            }
        }
    }
    return false;
}

现在已经拿到能够监听发布的事件的监听器了,那这个监听器要怎么执行呢?

6.2 执行监听器

回到 SimpleApplicationEventMulticaster#multicastEvent() 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
       if (executor != null && listener.supportsAsyncExecution()) {
          try {
             executor.execute(() -> invokeListener(listener, event));
          }
          catch (RejectedExecutionException ex) {
             // Probably on shutdown -> invoke listener locally instead
             invokeListener(listener, event);
          }
       }
       else {
          invokeListener(listener, event);
       }
    }
}

遍历监听器时,将调用 invokeListener() 方法执行监听器,其内部又会调用 doInvokeListener()

1
2
3
4
5
6
7
8
9
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
       listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        // --snip--
    }
}

最终其实是调用了 ApplicationListeneronApplicationEvent() 方法来执行监听器。

还记得示例中的监听器方法会被包装成哪个对象吗?

ApplicationListenerMethodAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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");
        }
    }
}

内部有四个主要逻辑:

  1. resolveArguments()
  2. shouldHandle()
  3. doInvoke()
  4. handleResult()

resolveArguments():根据传入的 ApplicationEvent 实例,获取执行监听器方法时使用的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected Object[] resolveArguments(ApplicationEvent event) {
    // 获取参数类型
    ResolvableType declaredEventType = getResolvableType(event);
    if (declaredEventType == null) {
        return null;
    }
    // 方法没有参数
    if (this.method.getParameterCount() == 0) {
        return new Object[0];
    }
    Class<?> declaredEventClass = declaredEventType.toClass();
    // 参数类型不是 ApplicationEvent,而是 PayloadApplicationEvent
    if (!ApplicationEvent.class.isAssignableFrom(declaredEventClass) &&
        event instanceof PayloadApplicationEvent<?> payloadEvent) {
        // 拿到内部的 payload
        Object payload = payloadEvent.getPayload();
        // 判断 payload 的类型是否与参数类型一直
        if (declaredEventClass.isInstance(payload)) {
            return new Object[] {payload};
        }
    }
    // 否则,直接返回
    return new Object[] {event};
}

里面又调用了 getResolvableType() 来获取参数类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private ResolvableType getResolvableType(ApplicationEvent event) {
    ResolvableType payloadType = null;
    // 如果是 PayloadApplicationEvent,就用拿它的泛型类型
    if (event instanceof PayloadApplicationEvent<?> payloadEvent) {
        ResolvableType eventType = payloadEvent.getResolvableType();
        if (eventType != null) {
            payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
        }
    }
    // 遍历当前监听器支持的事件类型
    for (ResolvableType declaredEventType : this.declaredEventTypes) {
        Class<?> eventClass = declaredEventType.toClass();
        // 支持的事件类型与 payload 的类型一样
        if (!ApplicationEvent.class.isAssignableFrom(eventClass) &&
            payloadType != null && declaredEventType.isAssignableFrom(payloadType)) {
            return declaredEventType;
        }
        // 支持的事件类型就是 event 对应的类型
        if (eventClass.isInstance(event)) {
            return declaredEventType;
        }
    }
    return null;
}

shouldHandle():根据包装的事件、执行监听器需要的参数判断是否应该执行监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
    if (args == null) {
        return false;
    }
    // 获取监听器的执行条件
    // 也就是 @EventListener 注解上的 condition 属性值
    String condition = getCondition();
    // 如果有值
    if (StringUtils.hasText(condition)) {
        Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");
        // 这个值是 SPEL 表达式,计算这个表达式,判断是否满足条件
        return this.evaluator.condition(
            condition, event, this.targetMethod, this.methodKey, args);
    }
    // 没有值直接返回 true
    return true;
}

doInvoke():执行事件监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Nullable
protected Object doInvoke(@Nullable Object... args) {
    // 获取监听器方法所在类对应的 Bean
    Object bean = getTargetBean();
    // Detect package-protected NullBean instance through equals(null) check
    if (bean.equals(null)) {
        return null;
    }
    // 设置访问权限
    ReflectionUtils.makeAccessible(this.method);
    try {
        // Kotlin 相关,忽略
        if (KotlinDetector.isSuspendingFunction(this.method)) {
            return CoroutinesUtils.invokeSuspendingFunction(this.method, bean, args);
        }
        // 反射调用方法
        return this.method.invoke(bean, args);
    }
    catch (IllegalArgumentException ex) {
        // --snip--
    }
}

看到这里,顿时恍然大悟,搞了半天,最终还是利用反射去执行的监听器方法。😞

handleResult():如果监听器方法还有返回值,继续处理返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@SuppressWarnings({"deprecation", "unchecked"})
protected void handleResult(Object result) {
    // 响应式相关
    if (reactiveStreamsPresent && new ReactiveResultHandler().subscribeToPublisher(result)) {
        if (logger.isTraceEnabled()) {
            logger.trace("Adapted to reactive result: " + result);
        }
    }
    else if (result instanceof CompletionStage<?> completionStage) {
        // 返回的是否是 CompletionStage 类型,比如 CompletableFuture
        completionStage.whenComplete((event, ex) -> {
            if (ex != null) {
                handleAsyncError(ex);
            }
            else if (event != null) {
                // 将结果作为事件,又发布
                publishEvents(event);
            }
        });
    }
    else if (result instanceof org.springframework.util.concurrent.ListenableFuture<?> listenableFuture) {
        // Spring 6.0 已标记为过期,忽略
        // 使用 CompletableFuture 代替
        listenableFuture.addCallback(this::publishEvents, this::handleAsyncError);
    }
    else {
        // 将结果作为事件,又发布
        publishEvents(result);
    }
}

调用 publishEvents() 方法,将当前事件监听器方法的返回值作为事件再次发布:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private void publishEvents(@Nullable Object result) {
    // 如果返回数组,
    if (result != null && result.getClass().isArray()) {
       Object[] events = ObjectUtils.toObjectArray(result);
       for (Object event : events) {
          publishEvent(event);
       }
    }
    else if (result instanceof Collection<?> events) {
       for (Object event : events) {
          publishEvent(event);
       }
    }
    else {
       publishEvent(result);
    }
}

private void publishEvent(@Nullable Object event) {
    if (event != null) {
       Assert.notNull(this.applicationContext, "ApplicationContext must not be null");
       this.applicationContext.publishEvent(event);
    }
}

也就是说,Spring 的事件监听机制支持“事件链(我编的词 😂)”。

修改原先的示例,试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@SpringBootApplication
public class SimpleSpringEventListenerTest {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SimpleSpringEventListenerTest.class, args);
        context.publishEvent(new UserRegisterEvent("成功注册用户: mofan"));
        context.close();
    }

    @Slf4j
    @Component
    private static class UserRegisterEventListener {
        @EventListener
        public EventChain doEvent(UserRegisterEvent event) {
            log.info("监听到用户注册事件: {}", event.info());
            return new EventChain("事件链");
        }

        @EventListener
        public void doChain(EventChain chain) {
            log.info("监听到事件链: {}", chain.info());
        }
    }

    private record UserRegisterEvent(String info) {
    }

    private record EventChain(String info) {
    }
}

运行 main() 方法后,控制台打印出:

监听到用户注册事件: 成功注册用户: mofan
监听到事件链: 事件链

7. 总结

Spring 的事件机制并不难,其实现基本与先前的猜想一致:

  • 容器启动阶段遍历所有的 Bean,解析 @EventListener 注解,包装成事件监听器
  • 发布事件后,遍历所有的事件监听器,找到支持对应事件类型的监听器,反射调用方法,完成监听器的执行

基本原理不难,但经过 SpringBoot 的层层封装后使得整条执行链路变得很长。如果对容器的启动过程、Spring 中的工具类不熟,那整个源码阅读过程就会变得异常艰辛。

还是那句话,哪有什么岁月静好,都是 SpringBoot 在为你负重前行。👻