上篇我们讲到实现事件监听可以使用实现ApplicationListener接口 Spring中ApplicationListener -【Spring底层原理】,如果有多个方法需要监听事件,那岂不是每个方法都要放在类中实现ApplicationListener接口,这样并不是很方便,所以spring为我们提供了另外一种方式实现事件监听:使用@EventListener注解
一、注解用法
注解源码如下,有如下作用:
- 可以作用在方法
- 参数可以是class数组,可以写多个事件
- 使用了该注解的方法,当容器中发布事件后,该方法会触发,类似实现ApplicationListener接口
/*
* @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
来进行处理的,后面会分析其源码。
二、实例分析
// 启动测试类
@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注解,方便让多个方法触发
三、源码分析
上面讲到是使用EventListenerMethodProcessor
这个处理器来解析方法上的EventListener注解,点进EventListenerMethodProcessor
查看,发现实现了SmartInitializingSingleton
接口,主要就是通过该接口实现的。
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {}
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
方法上打上断点,看看源码是何时调用该方法执行的。
通过方法调用栈,容器创建对象,调用refresh()方法刷新容器——>finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()初始化剩下的单实例bean
- 创建所有的单实例bean
- 获取所有创建好的单实例bean,判断各bean是否是SmartInitializingSingleton类型的
- 如果是则调用afterSingletonsInstantiated方法
这里便到了我们上面分析的SmartInitializingSingleton#afterSingletonsInstantiated方法,也就是@EventListener注解注解起作用的地方
@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();
}
}
}
四、总结
- IOC容器创建对象并refresh刷新
- finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()初始化剩下的单实例bean
- 创建所有的单实例bean
- 获取所有创建好的单实例bean,判断各bean是否是SmartInitializingSingleton类型的
- 如果是则调用afterSingletonsInstantiated方法
评论