使用Spring注解@EventListener实现监听原理

 更新时间:2024年08月13日 11:41:10   作者:菜腿1994  
这篇文章主要介绍了使用Spring注解@EventListener实现监听原理,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

@EventListener使用方式

package com.cyl.listener;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class CylOrderSecListener {

	@EventListener
	public void listen(ApplicationEvent event) {
		System.out.println(event);
	}
}

@EventListener实现原理

主要通过EventListenerMethodProcessor和DefaultEventListenerFactory这两个类实现。

  • EventListenerMethodProcessor的作用是识别所有使用eventListener注解的方法
  • DefaultEventListenerFactory将EventListenerMethodProcessor识别出的方法封装成为监听器类

以代码new AnnotationConfigApplicationContext为入口调试代码去讲解EventListenerMethodProcessor和DefaultEventListenerFactory如何去生效的

package com.cyl;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {

	public static void main(String[] args) {
		// 创建一个Spring容器
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		context.register(AppConfig.class);
		context.refresh();
    }
}

1.引入时机-获取bean定义

EventListenerMethodProcessor和DefaultEventListenerFactory的bean定义信息在容器初始化最开始阶段,DefaultListableBeanFactory实例化后,被注册到DefaultListableBeanFactory的beanDefinitionMap中。

执行new AnnotationConfigApplicationContext,会优先执行父类 GenericApplicationContex构造方法,实例化一个bean工厂

GenericApplicationContext执行完后,会实例化AnnotatedBeanDefinitionReader,可以理解为容器内一个bean定义阅读器,负责将bean定义注册到bean工厂中。

实例化AnnotatedBeanDefinitionReader会注册一些bean定义到bean工厂中,其中就包括了EventListenerMethodProcessor和DefaultEventListenerFactory。

2.实例化时机-new对象

只引入了bean定义,还未真正对bean进行实例化,实例化步骤是在spring执行refresh时

走到方法内,会调用

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)

关注代码184行,获取普通BeanFactoryPostProcessor类,而EventListenerMethodProcessor实现了BeanFactoryPostProcessor,此处打断点也会获取该类名

由于EventListenerMethodProcessor没有实现PriorityOrdered或者Ordered接口,所以就被放入了nonOrderedPostProcessorNames中最后被执行

当执行beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)会进行实例化走到EventListenerMethodProcessor的构造函数中

到此EventListenerMethodProcessor实例化好了,代码继续执行

会执行到EventListenerMethodProcessor.postProcessBeanFactory(),在这里实例化DefaultEventListenerFactory

3.作用时机->将加了EventListener注解的方法识别出来

并封装为监听器,加载spring容器中

当执行

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

初始化后,

因EventListenerMethodProcessor实现了SmartInitializingSingleton,

而所有实现SmartInitializingSingleton类对象都需要在所有对象初始化后再执行afterSingletonsInstantiated

即:

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
@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);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			// 获取合并后的BeanDefinition
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					// 获取FactoryBean对象
					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) {
							// 创建真正的Bean对象(getObject()返回的对象)
							getBean(beanName);
						}
					}
				}
				else {
					// 创建Bean对象
					getBean(beanName);
				}
			}
		}

		// 所有的非懒加载单例Bean都创建完了后
		// Trigger post-initialization callback for all applicable beans...
		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>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
				smartInitialize.end();
			}
		}
	}

当执行smartSingleton.afterSingletonsInstantiated();就会调到

org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated

EventListenerMethodProcessor真正的处理逻辑来了,主要看第38行关键方法

@Override
	public void afterSingletonsInstantiated() {
		ConfigurableListableBeanFactory beanFactory = this.beanFactory;
		Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
		String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
		for (String beanName : beanNames) {
			if (!ScopedProxyUtils.isScopedTarget(beanName)) {

				// 拿到当前Bean对象的类型
				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 {
                        //关键方法
						processBean(beanName, type);
					}
					catch (Throwable ex) {
						throw new BeanInitializationException("Failed to process @EventListener " +
								"annotation on bean with name '" + beanName + "'", ex);
					}
				}
			}
		}
	}

org.springframework.context.event.EventListenerMethodProcessor#processBean,关注下面代码的注释,主要逻辑就是会遍历所有单例池中的对象,找到对象中加@EventListener注解的方法,然后通过EventListenerFactory将方法设置成监听器,注册到spring容器中

private void processBean(final String beanName, final Class<?> targetType) {
		if (!this.nonAnnotatedClasses.contains(targetType) &&
				AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
				!isSpringContainerClass(targetType)) {

			// 找到所有加了@EventListener注解的方法
			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 = this.applicationContext;
				Assert.state(context != null, "No ApplicationContext set");
				List<EventListenerFactory> factories = this.eventListenerFactories;
				Assert.state(factories != null, "EventListenerFactory List not initialized");
				for (Method method : annotatedMethods.keySet()) {
					for (EventListenerFactory factory : factories) {
						// 利用EventListenerFactory来对加了@EventListener注解的方法生成ApplicationListener对象
						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);
				}
			}
		}
	}

发布事件,生效

容器初始化后,设置的监听器会收到容器初始化完成的事件,然后执行自定义的监听事件

容器初始化最后阶段,即执行org.springframework.context.support.AbstractApplicationContext#finishRefresh

最终效果图为:

总结

EventListenerMethodProcessor和DefaultEventListenerFactory两个类是注解EventListener的逻辑处理类,先在spring容器初始化阶段先显示引入这两个类的bean定义,然后spring容器在执行beanFactory的后置处理器逻辑时,对这两个类进行实例化;

最后待所有非懒加载单例bean都初始化完后,执行EventListenerMethodProcessor的afterSingletonsInstantiated即初始化后方法,识别出所有加了注解EventListener的方法,将这些方法用DefaultEventListenerFactory封装成监听器类,注册到spring容器中。

待发布事件时,再从spring容器中获取所有监听器类,回调监听方法。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java 字符串截取及常见场景与方法详解

    Java 字符串截取及常见场景与方法详解

    在 Java 开发中,截取字符串是一个非常常见的操作,无论是获取文件名还是提取某些特定内容,本文详细介绍了截取字符串最后一位及其他常见截取操作的多种方法,帮助开发者快速上手,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • java中@DateTimeFormat和@JsonFormat注解的使用

    java中@DateTimeFormat和@JsonFormat注解的使用

    本文主要介绍了java中@DateTimeFormat和@JsonFormat注解的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Java向上取整的几种常见实现方法

    Java向上取整的几种常见实现方法

    这篇文章主要介绍了Java向上取整的几种常见实现方法,包括整数除法技巧、Math.ceil()函数、手动检查余数、位运算和使用BigDecimal的setScale方法,每种方法都有其适用场景,选择合适的方法可以提高代码的性能和可读性,需要的朋友可以参考下
    2024-12-12
  • Java Thread之Sleep()使用方法总结

    Java Thread之Sleep()使用方法总结

    这篇文章主要介绍了Java Thread之Sleep()使用方法总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • Spring整合Mybatis的全过程

    Spring整合Mybatis的全过程

    这篇文章主要介绍了Spring整合Mybatis的全过程,包括spring配置文件书写映射器接口的实例代码,本文给大家介绍的非常详细,需要的朋友可以参考下
    2021-06-06
  • Spring入门实战之Profile详解

    Spring入门实战之Profile详解

    什么是spring profile?简单讲profile就是一组配置,不同profile提供不同组合的配置,程序运行时可以选择使用哪些profile来适应环境。下面这篇文章主要介绍了Spring中Profile实战的相关资料,需要的朋友可以参考借鉴。
    2017-02-02
  • 使用jaxws建立webservice客户端并实现soap消息的handler验证示例

    使用jaxws建立webservice客户端并实现soap消息的handler验证示例

    这篇文章主要介绍了使用jaxws建立webservice客户端并实现soap消息的handler验证示例,需要的朋友可以参考下
    2014-03-03
  • SpringMVC路径规则以及使用正则详解

    SpringMVC路径规则以及使用正则详解

    本文介绍了@RequestMapping路径通配符的用法,包括*和**的区别及其灵活位置,说明了通配符与路径变量可共用,并讲解了匹配优先级规则:路径越具体优先级越高,变量比通配符更精确
    2025-10-10
  • javac -encoding 用法详解

    javac -encoding 用法详解

    当我们编辑了一个Java源文件保存时,是以操作系统默认的字符编码保存的(Windows xp默认字符集是GBK)。这篇文章主要介绍了javac -encoding 用法详解,非常具有实用价值。
    2016-12-12
  • Spring的初始化前中后详细解读

    Spring的初始化前中后详细解读

    这篇文章主要介绍了Spring的初始化前中后详细解读,Spring 框架是一个非常流行的 Java 框架,它提供了一种轻量级的、可扩展的方式来构建企业级应用程序,在 Spring 的生命周期中,有三个重要的阶段,即初始化前、初始化、初始化后,需要的朋友可以参考下
    2023-09-09

最新评论