SpringBoot版本:2.0.2.RELEASE
SpringFramework版本:5.0.6.RELEASE
EventListenerMethodProcessor与DefaultEventListenerFactory是两个重要的类,它们在AnnotationConfigUtils#registerAnnotationConfigProcessors方法里被注册到BeanDefinitionRegistry去了。
在SpringBoot程序的程动过程中,在构造AnnotationConfigApplicationContext的时候会调用此方法。它的方法调用链如下:
AnnotationConfigUtils#registerAnnotationConfigProcessors部分代码如下:
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
....
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));
}
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;
}
@Override
public void afterSingletonsInstantiated() {
List<EventListenerFactory> factories = getEventListenerFactories();
ConfigurableApplicationContext context = getApplicationContext();
String[] beanNames = context.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
....
try {
processBean(factories, beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
大意就是从BeanFactory取出所有已注册类的beanNames, 然后挨个地将bean名字连同EventListenerFactory集合和bean的类型都交给processBean方法处理。
protected void processBean(
final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
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)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = getApplicationContext();
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
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);
}
context.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
在processBean方法体里,我们看到先把指定类型里面所有使用@EventListener标注的方法取出来,并存放在annotatedMethods变量里。然后经过双重循环,使得annotatedMethods变量里每个方法对象都被每个EventListenerFactory进行处理。EventListenerFactory#createApplicationListener会返回ApplicationListener,该ApplicationListener随后被注册到ConfigurableApplicationContext。
至此,我们虽然没有细看EventListenerFactory的细节,但我们知道此时已经将使用@EventListener标的方法转换为ApplicationListener,并融入到Spring Framework的事件与监听机制当中。
那么,我们来关注下这个过程发生的时机点:
从SpringBoot的启动过程中发布的事件来看,触发这个过程的时机在ApplicationPreparedEvent事件之后,ContextRefreshedEvent之前。从AbstractApplicationContext#refresh方法体代码可知,这个过程仅仅在发布ContextRefreshedEvent之前发生。
@Override
public void refresh() throws BeansException, IllegalStateException {
....
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
....
}
此时,AbstractApplicationContext才刚刚添加了Spring Framework的监听器,通过这个过程,补充了使用@EventListener标注监听器,接下来发布ContextRefreshedEvent事件时,SpringBoot监听器、SpringFramework监听器以及用户编程使用@EventListener标注的监听器都会有可能收到(还存在事件与监听器匹配的环节)。后续发布的事件也会传递到它们。
protected List<EventListenerFactory> getEventListenerFactories() {
Map<String, EventListenerFactory> beans = getApplicationContext().getBeansOfType(EventListenerFactory.class);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
return factories;
}
因为DefaultEventListenerFactory是该接口的唯一实现类,所以该方法返回的集合只有一个元素。
DefaultEventListenerFactory重载了EventListenerFactory接口的方法。supportsMethod方法在EventListenerMethodProcessor#processBean方法体内被调用。从代码的上下文来判断,此方法是用来校验DefaultEventListenerFactory是否可以支持使用@EventListener标注的方法监听器。DefaultEventListenerFactory#supportsMethod直接就返回true;createApplicationListener方法是在随后被调用,它使用ApplicationListenerMethodAdapter来封装@EventListener标注的方法监听器:
@Override
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
return new ApplicationListenerMethodAdapter(beanName, type, method);
}
从ApplicationListenerMethodAdapter名字来看,就知道又是采用了适配器模式。那么它的结构以及方法细节,在下节探讨。
从类的定义来看,它实现了GenericApplicationListener接口,也就是说它会重载supportsEventType方法和supportsSourceType方法 。
我们先观察其构造函数,它有三个形式参数:String beanName, Class> targetClass, Method method。这三参数都直接或者经过稍微的处理后存储到相应的属性变量里。然而,我们需要更多的关注它调用的resolveDeclaredEventTypes方法:
private List<ResolvableType> resolveDeclaredEventTypes(Method method, @Nullable EventListener ann) {
int count = method.getParameterCount();
if (count > 1) {
throw new IllegalStateException(
"Maximum one parameter is allowed for event listener method: " + method);
}
if (ann != null) {
Class<?>[] classes = ann.classes();
if (classes.length > 0) {
List<ResolvableType> types = new ArrayList<>(classes.length);
for (Class<?> eventType : classes) {
types.add(ResolvableType.forClass(eventType));
}
return types;
}
}
if (count == 0) {
throw new IllegalStateException(
"Event parameter is mandatory for event listener method: " + method);
}
return Collections.singletonList(ResolvableType.forMethodParameter(method, 0));
}
这条方法有返回值,让人第一时间就想到它是用于获取数据,确实它起到了获取数据的作用,然而它所做的事情还包含@EventListener标注使用的规范:
首先,在参数约束上,方法参数不能多于一个,并且如果@EventListene标注没有指定事件类型,则使用@EventListene标注的方法的形式参数(后文简称“方法参数”)必须得有一个;
其次,@EventListener的value属性的解析优先于方法参数的获取,也就是只要使用@EventListener标注时指定了监听的事件类型,无论是一个还是多个,都不再解析方法参数指定的事件类型;
还有,如果@EventListener没有指定事件类型,可通过方法参数指定事件类型。
构造函数调用resolveDeclaredEventTypes方法获取了这个监听器所支持的事件类型的集合,并存储于declaredEventTypes属性内。
在重载的supportsEventType方法里,declaredEventTypes属性被用于判断参数的类型是否为集合内某个事件类型或者其子类,如果不是的话,进一步检查参数是否为泛型事件PayloadEvent,如果是的话检查泛型的具体类型是否符合;在重载的supportsSourceType方法很简单,直接返回了true。
在EventListenerMethodProcessor#processBean的方法里,@EventListener标注的方法被封装成ApplicationListenerMethodAdapter监听器,并添加到ConfigurableApplicationContext的监听器集合里。当ConfigurableApplicationContext发布事件时,在分组缓存建立前,都会进行事件类型与监听器的匹配。AbstractApplicationEventMulticaster#supportsEvent,如图:
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
因为ApplicationListenerMethodAdapter实现了GenericApplicationListener接口,所以无需进一步地封装成GenericApplicationListenerAdapter,直接通过supportsEventType方法和supportsSourceType方法的返回值来判断是否匹配。前文我们发现ApplicationListenerMethodAdapter#supportsSourceType方法直接返回true,所以在使用@EventListener时设置的classes属性或者方法参数的事件类型成为了关键。