Spring中的EventListenerMethodProcessor組件詳解
EventListenerMethodProcessor組件
1. 概述
EventListenerMethodProcessor 是 Spring 事件機(jī)制中非常重要的一個(gè)組件。它管理了一組EventListenerFactory組件,用來(lái)將應(yīng)用中每個(gè)使用@EventListener注解定義的事件監(jiān)聽(tīng)方法變成一個(gè)ApplicationListener實(shí)例注冊(cè)到容器。換句話講,框架開(kāi)發(fā)者,或者應(yīng)用開(kāi)發(fā)者使用注解@EventListener定義的事件處理方法,如果沒(méi)有EventListenerMethodProcessor的發(fā)現(xiàn)和注冊(cè),是不會(huì)被容器看到和使用的。
EventListenerMethodProcessor實(shí)現(xiàn)了如下三個(gè)接口 :
- ApplicationContextAware
- BeanFactoryPostProcessor
- SmartInitializingSingleton
通過(guò)實(shí)現(xiàn)接口ApplicationContextAware,容器會(huì)將當(dāng)前應(yīng)用上下文ApplicationContext告訴EventListenerMethodProcessor,這是EventListenerMethodProcessor用于檢測(cè)發(fā)現(xiàn)@EventListener注解方法的來(lái)源,生成的ApplicationListener也放到該應(yīng)用上下文。
通過(guò)實(shí)現(xiàn)接口BeanFactoryPostProcessor,EventListenerMethodProcessor變成了一個(gè)BeanFactory的后置處理器,也就是說(shuō),在容器啟動(dòng)過(guò)程中的后置處理階段,啟動(dòng)過(guò)程會(huì)調(diào)用EventListenerMethodProcessor的方法postProcessBeanFactory。在這個(gè)方法中,EventListenerMethodProcessor會(huì)找到容器中所有類型為EventListenerFactory的bean,最終@EventListener注解方法的檢測(cè)發(fā)現(xiàn),以及ApplicationListener實(shí)例的生成和注冊(cè),靠的是這些EventListenerFactory組件。
而通過(guò)實(shí)現(xiàn)接口SmartInitializingSingleton,在容器啟動(dòng)過(guò)程中所有單例bean創(chuàng)建階段(此階段完成前,這些bean并不會(huì)供外部使用)的末尾,EventListenerMethodProcessor的方法afterSingletonsInstantiated會(huì)被調(diào)用。在這里,EventListenerMethodProcessor會(huì)便利容器中所有的bean,進(jìn)行@EventListener注解方法的檢測(cè)發(fā)現(xiàn),以及ApplicationListener實(shí)例的生成和注冊(cè)。
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());
// 用于記錄檢測(cè)發(fā)現(xiàn)`@EventListener`注解方法,生成和注冊(cè)`ApplicationListener`實(shí)例的應(yīng)用上下文
@Nullable
private ConfigurableApplicationContext applicationContext;
// 記錄當(dāng)前 BeanFactory, 實(shí)際上這個(gè)變量可用可不用,因?yàn)橥ㄟ^(guò) applicationContext 也可以找到
// 當(dāng)前 BeanFactory
@Nullable
private ConfigurableListableBeanFactory beanFactory;
// 記錄從容器中找到的所有 EventListenerFactory
@Nullable
private List<EventListenerFactory> eventListenerFactories;
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();
// 緩存機(jī)制,記住那些根本任何方法上沒(méi)有使用注解 @EventListener 的類,避免處理過(guò)程中二次處理
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 組件
// 常見(jiàn)的一些 EventListenerFactory :
// TransactionalEventListenerFactory --
// 用于支持使用 @TransactionalEventListener 注解的事件監(jiān)聽(tīng)器, @TransactionalEventListener 是一種特殊的
// @EventListener,它定義的事件監(jiān)聽(tīng)器應(yīng)用于事務(wù)提交或者回滾的某些特殊時(shí)機(jī),
// 由 ProxyTransactionManagementConfiguration 注冊(cè)到容器
// 注冊(cè)到容器
// DefaultEventListenerFactory -- 系統(tǒng)缺省, 最低優(yōu)先級(jí),如果其他 EventListenerFactory 都不支持的時(shí)候使用
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) {
// 遍歷每個(gè)bean組件,檢測(cè)其中`@EventListener`注解方法,生成和注冊(cè)`ApplicationListener`實(shí)例
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 {
// 注意這一行,針對(duì)一個(gè)bean的真正的`@EventListener`注解方法檢測(cè),
// `ApplicationListener`實(shí)例生成注冊(cè)發(fā)生在這里
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}
// 該方法拿到某個(gè)bean的名稱和它的目標(biāo)類,在這個(gè)范圍上檢測(cè)`@EventListener`注解方法,
// 生成和注冊(cè)`ApplicationListener`實(shí)例
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 {
// *** 注意這里, 這里檢測(cè)當(dāng)前類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)) {
// 如果當(dāng)前類 targetType 中沒(méi)有任何使用了 注解 @EventListener 的方法,則將該類保存到
// 緩存 nonAnnotatedClasses, 從而避免當(dāng)前處理方法重入該類,其目的應(yīng)該是為了提高效率,
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// 發(fā)現(xiàn)當(dāng)前類 targetType 中有些方法使用了注解 @EventListener,現(xiàn)在根據(jù)這些方法上的信息
// 對(duì)應(yīng)地創(chuàng)建和注冊(cè)ApplicationListener實(shí)例
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
// 注意,這里使用到了 this.eventListenerFactories, 這些 EventListenerFactory 是在
// 該類 postProcessBeanFactory 方法調(diào)用時(shí)被記錄的
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)) {
// 如果當(dāng)前 EventListenerFactory factory 支持處理該 @EventListener 注解的方法,
// 則使用它創(chuàng)建 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 實(shí)例注冊(cè)到容器
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));
}
}到此這篇關(guān)于Spring中的EventListenerMethodProcessor組件詳解的文章就介紹到這了,更多相關(guān)EventListenerMethodProcessor組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- spring中EventListener的使用方式
- spring的TransactionalEventListener事務(wù)感知源碼解析
- SpringBoot使用ApplicationEvent&Listener完成業(yè)務(wù)解耦
- SpringBoot中ApplicationEvent和ApplicationListener用法小結(jié)
- Spring注解驅(qū)動(dòng)之@EventListener注解使用方式
- Spring事件監(jiān)聽(tīng)器之@EventListener原理分析
- Spring?@EventListener?異步中使用condition的問(wèn)題及處理
相關(guān)文章
java實(shí)現(xiàn)1M圖片壓縮優(yōu)化到100kb實(shí)現(xiàn)示例
這篇文章主要為大家介紹了java實(shí)現(xiàn)1M圖片壓縮優(yōu)化到100kb示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
將Java程序的輸出結(jié)果寫(xiě)到txt文件中的方法
今天小編就為大家分享一篇將Java程序的輸出結(jié)果寫(xiě)到txt文件中的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Java實(shí)戰(zhàn)之郵件的撰寫(xiě)和發(fā)送
這篇文章主要為大家詳細(xì)介紹了通過(guò)Java代碼實(shí)現(xiàn)郵件的撰寫(xiě)和發(fā)送功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的小伙伴們可以學(xué)習(xí)一下2021-11-11
java this 用法詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了java this 用法詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03
Spring?JPA?deleteInBatch導(dǎo)致StackOverflow問(wèn)題
這篇文章主要介紹了Spring?JPA?deleteInBatch導(dǎo)致StackOverflow問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
mybatis主表與明細(xì)表一對(duì)多的同時(shí)插入操作方法
對(duì)主表(采購(gòu)申請(qǐng)表)和明細(xì)表(申請(qǐng)物資表)同時(shí)進(jìn)行插入操作insert,怎么實(shí)現(xiàn)呢,下面給大家分享mybatis主表與明細(xì)表一對(duì)多的同時(shí)插入操作方法,感興趣的朋友一起看看吧2023-02-02
SpringBoot?項(xiàng)目打成?jar后加載外部配置文件的操作方法
這篇文章主要介紹了SpringBoot?項(xiàng)目打成?jar后加載外部配置文件的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
SpringBootTest測(cè)試時(shí)不啟動(dòng)程序的問(wèn)題
這篇文章主要介紹了SpringBootTest測(cè)試時(shí)不啟動(dòng)程序的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01

