亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用Spring注解@EventListener實現(xiàn)監(jiān)聽原理

 更新時間:2024年08月13日 11:41:10   作者:菜腿1994  
這篇文章主要介紹了使用Spring注解@EventListener實現(xiàn)監(jiān)聽原理,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

@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實現(xiàn)原理

主要通過EventListenerMethodProcessor和DefaultEventListenerFactory這兩個類實現(xiàn)。

  • EventListenerMethodProcessor的作用是識別所有使用eventListener注解的方法
  • DefaultEventListenerFactory將EventListenerMethodProcessor識別出的方法封裝成為監(jiān)聽器類

以代碼new AnnotationConfigApplicationContext為入口調(diào)試代碼去講解EventListenerMethodProcessor和DefaultEventListenerFactory如何去生效的

package com.cyl;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {

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

1.引入時機-獲取bean定義

EventListenerMethodProcessor和DefaultEventListenerFactory的bean定義信息在容器初始化最開始階段,DefaultListableBeanFactory實例化后,被注冊到DefaultListableBeanFactory的beanDefinitionMap中。

執(zhí)行new AnnotationConfigApplicationContext,會優(yōu)先執(zhí)行父類 GenericApplicationContex構(gòu)造方法,實例化一個bean工廠

GenericApplicationContext執(zhí)行完后,會實例化AnnotatedBeanDefinitionReader,可以理解為容器內(nèi)一個bean定義閱讀器,負(fù)責(zé)將bean定義注冊到bean工廠中。

實例化AnnotatedBeanDefinitionReader會注冊一些bean定義到bean工廠中,其中就包括了EventListenerMethodProcessor和DefaultEventListenerFactory。

2.實例化時機-new對象

只引入了bean定義,還未真正對bean進(jìn)行實例化,實例化步驟是在spring執(zhí)行refresh時

走到方法內(nèi),會調(diào)用

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

關(guān)注代碼184行,獲取普通BeanFactoryPostProcessor類,而EventListenerMethodProcessor實現(xiàn)了BeanFactoryPostProcessor,此處打斷點也會獲取該類名

由于EventListenerMethodProcessor沒有實現(xiàn)PriorityOrdered或者Ordered接口,所以就被放入了nonOrderedPostProcessorNames中最后被執(zhí)行

當(dāng)執(zhí)行beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)會進(jìn)行實例化走到EventListenerMethodProcessor的構(gòu)造函數(shù)中

到此EventListenerMethodProcessor實例化好了,代碼繼續(xù)執(zhí)行

會執(zhí)行到EventListenerMethodProcessor.postProcessBeanFactory(),在這里實例化DefaultEventListenerFactory

3.作用時機->將加了EventListener注解的方法識別出來

并封裝為監(jiān)聽器,加載spring容器中

當(dāng)執(zhí)行

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

初始化后,

因EventListenerMethodProcessor實現(xiàn)了SmartInitializingSingleton,

而所有實現(xiàn)SmartInitializingSingleton類對象都需要在所有對象初始化后再執(zhí)行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) {
							// 創(chuàng)建真正的Bean對象(getObject()返回的對象)
							getBean(beanName);
						}
					}
				}
				else {
					// 創(chuàng)建Bean對象
					getBean(beanName);
				}
			}
		}

		// 所有的非懶加載單例Bean都創(chuàng)建完了后
		// 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();
			}
		}
	}

當(dāng)執(zhí)行smartSingleton.afterSingletonsInstantiated();就會調(diào)到

org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated

EventListenerMethodProcessor真正的處理邏輯來了,主要看第38行關(guān)鍵方法

@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)) {

				// 拿到當(dāng)前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 {
                        //關(guān)鍵方法
						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,關(guān)注下面代碼的注釋,主要邏輯就是會遍歷所有單例池中的對象,找到對象中加@EventListener注解的方法,然后通過EventListenerFactory將方法設(shè)置成監(jiān)聽器,注冊到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);
				}
			}
		}
	}

發(fā)布事件,生效

容器初始化后,設(shè)置的監(jiān)聽器會收到容器初始化完成的事件,然后執(zhí)行自定義的監(jiān)聽事件

容器初始化最后階段,即執(zhí)行org.springframework.context.support.AbstractApplicationContext#finishRefresh

最終效果圖為:

總結(jié)

EventListenerMethodProcessor和DefaultEventListenerFactory兩個類是注解EventListener的邏輯處理類,先在spring容器初始化階段先顯示引入這兩個類的bean定義,然后spring容器在執(zhí)行beanFactory的后置處理器邏輯時,對這兩個類進(jìn)行實例化;

最后待所有非懶加載單例bean都初始化完后,執(zhí)行EventListenerMethodProcessor的afterSingletonsInstantiated即初始化后方法,識別出所有加了注解EventListener的方法,將這些方法用DefaultEventListenerFactory封裝成監(jiān)聽器類,注冊到spring容器中。

待發(fā)布事件時,再從spring容器中獲取所有監(jiān)聽器類,回調(diào)監(jiān)聽方法。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Fluent Mybatis零xml配置實現(xiàn)復(fù)雜嵌套查詢

    Fluent Mybatis零xml配置實現(xiàn)復(fù)雜嵌套查詢

    本文主要介紹了Fluent Mybatis零xml配置實現(xiàn)復(fù)雜嵌套查詢,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • SpringAMQP消息隊列實戰(zhàn)教程

    SpringAMQP消息隊列實戰(zhàn)教程

    這篇文章主要介紹了SpringAMQP消息隊列的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2024-02-02
  • 用StopWatch優(yōu)雅替代currentTimeMillis計算程序執(zhí)行耗時

    用StopWatch優(yōu)雅替代currentTimeMillis計算程序執(zhí)行耗時

    別再用System.currentTimeMillis()計算程序執(zhí)行耗時了,擁抱StopWatch優(yōu)雅來優(yōu)雅的計算,代碼更簡潔效率更高,本文帶你了解StopWatch的使用
    2021-09-09
  • 一文讓你搞懂如何手寫一個redis分布式鎖

    一文讓你搞懂如何手寫一個redis分布式鎖

    既然要搞懂Redis分布式鎖,那肯定要有一個需要它的場景。高并發(fā)售票問題就是一個經(jīng)典案例。本文就來利用這個場景手寫一個redis分布式鎖,讓你徹底搞懂它
    2022-11-11
  • Java實現(xiàn)Fast DFS、服務(wù)器、OSS上傳功能

    Java實現(xiàn)Fast DFS、服務(wù)器、OSS上傳功能

    這篇文章主要介紹了Java實現(xiàn)Fast DFS、服務(wù)器、OSS上傳功能,在實際的業(yè)務(wù)中,可以根據(jù)客戶的需求設(shè)置不同的文件上傳需求,支持普通服務(wù)器上傳+分布式上傳(Fast DFS)+云服務(wù)上傳OSS(OSS),需要的朋友可以參考下
    2024-04-04
  • SpringBoot如何返回頁面的實現(xiàn)方法

    SpringBoot如何返回頁面的實現(xiàn)方法

    SpringBoot中使用Controller和頁面的結(jié)合能夠很好地實現(xiàn)用戶的功能及頁面數(shù)據(jù)的傳遞。本文介紹了如何實現(xiàn)頁面的返回以及這里面所包含的坑,感興趣的可以了解一下
    2021-07-07
  • Java?file類中renameTo方法操作實例

    Java?file類中renameTo方法操作實例

    renameTo()方法是File類的一部分,renameTo()函數(shù)用于將文件的抽象路徑名重命名為給定的路徑名??,下面這篇文章主要給大家介紹了關(guān)于Java?file類中renameTo方法操作的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • java常用工具類 UUID、Map工具類

    java常用工具類 UUID、Map工具類

    這篇文章主要為大家詳細(xì)介紹了Java常用工具類,包括UUID工具類、Map工具類,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • Java中常用的設(shè)計模式之責(zé)任鏈模式詳解

    Java中常用的設(shè)計模式之責(zé)任鏈模式詳解

    這篇文章主要為大家詳細(xì)介紹了Java中常用的設(shè)計模式之責(zé)任鏈模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • idea導(dǎo)入項目爆紅問題記錄以及解決

    idea導(dǎo)入項目爆紅問題記錄以及解決

    這篇文章主要介紹了idea導(dǎo)入項目爆紅問題記錄以及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評論