EventListenerMethodProcessor
是 Spring
事件机制中非常重要的一个组件。它管理了一组EventListenerFactory
组件,用来将应用中每个使用@EventListener
注解定义的事件监听方法变成一个ApplicationListener
实例注册到容器。换句话讲,框架开发者,或者应用开发者使用注解@EventListener
定义的事件处理方法,如果没有EventListenerMethodProcessor
的发现和注册,是不会被容器看到和使用的。
EventListenerMethodProcessor
实现了如下三个接口 :
ApplicationContextAware
BeanFactoryPostProcessor
SmartInitializingSingleton
通过实现接口ApplicationContextAware
,容器会将当前应用上下文ApplicationContext
告诉EventListenerMethodProcessor
,这是EventListenerMethodProcessor
用于检测发现@EventListener
注解方法的来源,生成的ApplicationListener
也放到该应用上下文。
通过实现接口BeanFactoryPostProcessor
,EventListenerMethodProcessor
变成了一个BeanFactory
的后置处理器,也就是说,在容器启动过程中的后置处理阶段,启动过程会调用EventListenerMethodProcessor
的方法postProcessBeanFactory
。在这个方法中,EventListenerMethodProcessor
会找到容器中所有类型为EventListenerFactory
的bean
,最终@EventListener
注解方法的检测发现,以及ApplicationListener
实例的生成和注册,靠的是这些EventListenerFactory
组件。
关于调用
EventListenerMethodProcessor.postProcessBeanFactory
更多的信息,可以参考这篇文章。
而通过实现接口SmartInitializingSingleton
,在容器启动过程中所有单例bean
创建阶段(此阶段完成前,这些bean
并不会供外部使用)的末尾,EventListenerMethodProcessor
的方法afterSingletonsInstantiated
会被调用。在这里,EventListenerMethodProcessor
会便利容器中所有的bean
,进行@EventListener
注解方法的检测发现,以及ApplicationListener
实例的生成和注册。
关于接口
SmartInitializingSingleton
定义的afterSingletonsInstantiated
方法的调用,可以参考这篇文章
代码版本 : Spring Context 5.2.0.RELEASE
package org.springframework.context.event;
//... 省略 import
/**
* Registers {@link EventListener} methods as individual {@link ApplicationListener} instances.
* Implements {@link BeanFactoryPostProcessor} (as of 5.1) primarily for early retrieval,
* avoiding AOP checks for this processor bean and its {@link EventListenerFactory} delegates.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.2
* @see EventListenerFactory
* @see DefaultEventListenerFactory
*/
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
protected final Log logger = LogFactory.getLog(getClass());
// 用于记录检测发现`@EventListener`注解方法,生成和注册`ApplicationListener`实例的应用上下文
@Nullable
private ConfigurableApplicationContext applicationContext;
// 记录当前 BeanFactory, 实际上这个变量可用可不用,因为通过 applicationContext 也可以找到
// 当前 BeanFactory
@Nullable
private ConfigurableListableBeanFactory beanFactory;
// 记录从容器中找到的所有 EventListenerFactory
@Nullable
private List<EventListenerFactory> eventListenerFactories;
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
// 缓存机制,记住那些根本任何方法上没有使用注解 @EventListener 的类,避免处理过程中二次处理
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext,
"ApplicationContext does not implement ConfigurableApplicationContext");
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
// 从容器中找到所有的 EventListenerFactory 组件
// 常见的一些 EventListenerFactory :
// TransactionalEventListenerFactory --
// 用于支持使用 @TransactionalEventListener 注解的事件监听器, @TransactionalEventListener 是一种特殊的
// @EventListener,它定义的事件监听器应用于事务提交或者回滚的某些特殊时机,
// 由 ProxyTransactionManagementConfiguration 注册到容器
// 注册到容器
// DefaultEventListenerFactory -- 系统缺省, 最低优先级,如果其他 EventListenerFactory 都不支持的时候使用
Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
this.eventListenerFactories = factories;
}
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
// 这里获取容器中所有bean组件的名称,
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
// 遍历每个bean组件,检测其中`@EventListener`注解方法,生成和注册`ApplicationListener`实例
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
try {
// 注意这一行,针对一个bean的真正的`@EventListener`注解方法检测,
// `ApplicationListener`实例生成注册发生在这里
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
// 该方法拿到某个bean的名称和它的目标类,在这个范围上检测`@EventListener`注解方法,
// 生成和注册`ApplicationListener`实例
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
// *** 注意这里, 这里检测当前类targetType上使用了注解 @EventListener 的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
// 如果当前类 targetType 中没有任何使用了 注解 @EventListener 的方法,则将该类保存到
// 缓存 nonAnnotatedClasses, 从而避免当前处理方法重入该类,其目的应该是为了提高效率,
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// 发现当前类 targetType 中有些方法使用了注解 @EventListener,现在根据这些方法上的信息
// 对应地创建和注册ApplicationListener实例
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
// 注意,这里使用到了 this.eventListenerFactories, 这些 EventListenerFactory 是在
// 该类 postProcessBeanFactory 方法调用时被记录的
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
// 如果当前 EventListenerFactory factory 支持处理该 @EventListener 注解的方法,
// 则使用它创建 ApplicationListener
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
// 将所生成的 ApplicationListener 实例注册到容器
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
/**
* Determine whether the given class is an {@code org.springframework}
* bean class that is not annotated as a user or test {@link Component}...
* which indicates that there is no {@link EventListener} to be found there.
* @since 5.1
*/
private static boolean isSpringContainerClass(Class<?> clazz) {
return (clazz.getName().startsWith("org.springframework.") &&
!AnnotatedElementUtils.isAnnotated(ClassUtils.getUserClass(clazz), Component.class));
}
}