封面来源:碧蓝航线 愚者的天平 活动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 在为你负重前行。👻