EventListener注解 -【Spring底层原理】

blog59

上篇我们讲到实现事件监听可以使用实现ApplicationListener接口 Spring中ApplicationListener -【Spring底层原理】,如果有多个方法需要监听事件,那岂不是每个方法都要放在类中实现ApplicationListener接口,这样并不是很方便,所以spring为我们提供了另外一种方式实现事件监听:使用@EventListener注解

一、注解用法

注解源码如下,有如下作用:

  • 可以作用在方法
  • 参数可以是class数组,可以写多个事件
  • 使用了该注解的方法,当容器中发布事件后,该方法会触发,类似实现ApplicationListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
java复制代码 /*
* @author Stephane Nicoll
* @author Sam Brannen
* @since 4.2
* @see EventListenerMethodProcessor
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {

@AliasFor("classes")
Class<?>[] value() default {};

@AliasFor("value")
Class<?>[] classes() default {};

String condition() default "";
}

从注释可以看到是使用EventListenerMethodProcessor这个处理器来解析方法上的EventListener注解,EventListenerMethodProcessor主要则是通过其实现的接口SmartInitializingSingleton来进行处理的,后面会分析其源码。

二、实例分析

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
java复制代码// 启动测试类
@Test
public void TestMain(){
// 创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// 自己发布一个事件
applicationContext.publishEvent(new ApplicationEvent("自己发布的事件") {
});
applicationContext.close();
}

// 事件触发
@Service
public class UserService {
// 当容器中发布事件后,该方法会触发
@EventListener(classes = {ApplicationEvent.class})
public void listener1(ApplicationEvent event){
System.out.println("监听到的事件1:" + event);
}
@EventListener(classes = {ApplicationEvent.class})
public void listener2(ApplicationEvent event){
System.out.println("监听到的事件2:" + event);
}
}

// 配置类
@ComponentScan("listener")
@Configuration
public class AppConfig {
}

运行启动类,可以看到,两个事件都被触发了,使用@EventListener注解,方便让多个方法触发

image-20210324135958362

三、源码分析

上面讲到是使用EventListenerMethodProcessor这个处理器来解析方法上的EventListener注解,点进EventListenerMethodProcessor查看,发现实现了SmartInitializingSingleton接口,主要就是通过该接口实现的。

1
java复制代码public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码public interface SmartInitializingSingleton {

/**
* Invoked right at the end of the singleton pre-instantiation phase,
* with a guarantee that all regular singleton beans have been created
* already. {@link ListableBeanFactory#getBeansOfType} calls within
* this method won't trigger accidental side effects during bootstrap.
* <p><b>NOTE:</b> This callback won't be triggered for singleton beans
* lazily initialized on demand after {@link BeanFactory} bootstrap,
* and not for any other bean scope either. Carefully use it for beans
* with the intended bootstrap semantics only.
*/
void afterSingletonsInstantiated();

}

SmartInitializingSingleton接口有个afterSingletonsInstantiated方法,当单实例bean全部创建完成,会触发这个接口,执行afterSingletonsInstantiated方法,类似于ContextRefreshedEvent

我们在afterSingletonsInstantiated方法上打上断点,看看源码是何时调用该方法执行的。

image-20210324144953217

通过方法调用栈,容器创建对象,调用refresh()方法刷新容器——>finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()初始化剩下的单实例bean

  • 创建所有的单实例bean
  • 获取所有创建好的单实例bean,判断各bean是否是SmartInitializingSingleton类型的
  • 如果是则调用afterSingletonsInstantiated方法

这里便到了我们上面分析的SmartInitializingSingleton#afterSingletonsInstantiated方法,也就是@EventListener注解注解起作用的地方

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
java复制代码@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}

// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// 遍历beanName,创建bean,即非懒加载单实例bean的初始化
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 创建对象
getBean(beanName);
}
}
}

// Trigger post-initialization callback for all applicable beans...
// 创建完bean后判断各bean是否实现了SmartInitializingSingleton,如果是则执行 smartSingleton.afterSingletonsInstantiated()方法
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// 执行afterSingletonsInstantiated
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}

四、总结

  1. IOC容器创建对象并refresh刷新
  2. finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()初始化剩下的单实例bean
    1. 创建所有的单实例bean
    2. 获取所有创建好的单实例bean,判断各bean是否是SmartInitializingSingleton类型的
    3. 如果是则调用afterSingletonsInstantiated方法

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%