Spring中的EventListenerMethodProcessor组件详解

 更新时间:2023年12月25日 10:02:52   作者:安迪源文  
这篇文章主要介绍了Spring中的EventListenerMethodProcessor组件详解,EventListenerMethodProcessor 是 Spring 事件机制中非常重要的一个组件,它管理了一组EventListenerFactory组件,用来将应用中每个使用@EventListener注解定义的事件监听,需要的朋友可以参考下

EventListenerMethodProcessor组件

1. 概述

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组件。

而通过实现接口SmartInitializingSingleton,在容器启动过程中所有单例bean创建阶段(此阶段完成前,这些bean并不会供外部使用)的末尾,EventListenerMethodProcessor的方法afterSingletonsInstantiated会被调用。在这里,EventListenerMethodProcessor会便利容器中所有的bean,进行@EventListener注解方法的检测发现,以及ApplicationListener实例的生成和注册。

2. 源代码

代码版本 : 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));
	}
}

到此这篇关于Spring中的EventListenerMethodProcessor组件详解的文章就介绍到这了,更多相关EventListenerMethodProcessor组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中for循环遍历删除操作方法

    Java中for循环遍历删除操作方法

    在Java中,有些场景需要遍历集合中的元素,然后根据条件进行删除元素的操作,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-11-11
  • Java实现随机出题,10道10以内加减法计算代码实例

    Java实现随机出题,10道10以内加减法计算代码实例

    这篇文章主要介绍了Java实现随机出题,10道10以内加减法计算,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • Resilience4J通过yml设置circuitBreaker的方法

    Resilience4J通过yml设置circuitBreaker的方法

    Resilience4j是一个轻量级、易于使用的容错库,其灵感来自Netflix Hystrix,但专为Java 8和函数式编程设计,这篇文章主要介绍了Resilience4J通过yml设置circuitBreaker的方法,需要的朋友可以参考下
    2022-10-10
  • Spring中的@Scheduled源码解析

    Spring中的@Scheduled源码解析

    这篇文章主要介绍了Spring中的@Scheduled源码解析,定时任务调度的基础是ScheduledAnnotationBeanPostProcessor类,这是一个实现了BeanPostProcessor接口的后置处理器,需要的朋友可以参考下
    2023-09-09
  • 详解MybatisPlus集成nacos导致druid连接不上数据库

    详解MybatisPlus集成nacos导致druid连接不上数据库

    这篇文章主要介绍了详解MybatisPlus集成nacos导致druid连接不上数据库,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Java业务校验工具实现方法

    Java业务校验工具实现方法

    这篇文章主要介绍了Java业务校验工具实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Java中BeanUtils.copyProperties()详解及应用场景

    Java中BeanUtils.copyProperties()详解及应用场景

    BeanUtils.copyProperties()是Apache Commons BeanUtils提供的方法,用于Java对象间属性的复制,特别适用于DTO、VO和Entity之间的数据传递,这篇文章主要介绍了Java中BeanUtils.copyProperties()详解及应用场景的相关资料,需要的朋友可以参考下
    2024-09-09
  • springboot中如何引入AOP切面编程

    springboot中如何引入AOP切面编程

    这篇文章主要介绍了springboot中如何引入AOP切面编程问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java直接调用本地大模型文件实现对话机器人

    Java直接调用本地大模型文件实现对话机器人

    这篇文章主要为大家详细介绍了Java直接调用本地大模型文件实现对话机器人的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下
    2026-05-05
  • Spring中如何获取request的方法汇总及其线程安全性分析

    Spring中如何获取request的方法汇总及其线程安全性分析

    这篇文章主要给大家介绍了关于Spring中如何获取request的方法汇总及其线程安全性分析的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-04-04

最新评论