最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用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.引入時機(jī)-獲取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.實例化時機(jī)-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.作用時機(jī)->將加了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)文章

  • Java 字符串截取及常見場景與方法詳解

    Java 字符串截取及常見場景與方法詳解

    在 Java 開發(fā)中,截取字符串是一個非常常見的操作,無論是獲取文件名還是提取某些特定內(nèi)容,本文詳細(xì)介紹了截取字符串最后一位及其他常見截取操作的多種方法,幫助開發(fā)者快速上手,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • java中@DateTimeFormat和@JsonFormat注解的使用

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

    本文主要介紹了java中@DateTimeFormat和@JsonFormat注解的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Java向上取整的幾種常見實現(xiàn)方法

    Java向上取整的幾種常見實現(xiàn)方法

    這篇文章主要介紹了Java向上取整的幾種常見實現(xiàn)方法,包括整數(shù)除法技巧、Math.ceil()函數(shù)、手動檢查余數(shù)、位運(yùn)算和使用BigDecimal的setScale方法,每種方法都有其適用場景,選擇合適的方法可以提高代碼的性能和可讀性,需要的朋友可以參考下
    2024-12-12
  • Java Thread之Sleep()使用方法總結(jié)

    Java Thread之Sleep()使用方法總結(jié)

    這篇文章主要介紹了Java Thread之Sleep()使用方法總結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Spring整合Mybatis的全過程

    Spring整合Mybatis的全過程

    這篇文章主要介紹了Spring整合Mybatis的全過程,包括spring配置文件書寫映射器接口的實例代碼,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-06-06
  • Spring入門實戰(zhàn)之Profile詳解

    Spring入門實戰(zhàn)之Profile詳解

    什么是spring profile?簡單講profile就是一組配置,不同profile提供不同組合的配置,程序運(yùn)行時可以選擇使用哪些profile來適應(yīng)環(huán)境。下面這篇文章主要介紹了Spring中Profile實戰(zhàn)的相關(guān)資料,需要的朋友可以參考借鑒。
    2017-02-02
  • 使用jaxws建立webservice客戶端并實現(xiàn)soap消息的handler驗證示例

    使用jaxws建立webservice客戶端并實現(xiàn)soap消息的handler驗證示例

    這篇文章主要介紹了使用jaxws建立webservice客戶端并實現(xiàn)soap消息的handler驗證示例,需要的朋友可以參考下
    2014-03-03
  • SpringMVC路徑規(guī)則以及使用正則詳解

    SpringMVC路徑規(guī)則以及使用正則詳解

    本文介紹了@RequestMapping路徑通配符的用法,包括*和**的區(qū)別及其靈活位置,說明了通配符與路徑變量可共用,并講解了匹配優(yōu)先級規(guī)則:路徑越具體優(yōu)先級越高,變量比通配符更精確
    2025-10-10
  • javac -encoding 用法詳解

    javac -encoding 用法詳解

    當(dāng)我們編輯了一個Java源文件保存時,是以操作系統(tǒng)默認(rèn)的字符編碼保存的(Windows xp默認(rèn)字符集是GBK)。這篇文章主要介紹了javac -encoding 用法詳解,非常具有實用價值。
    2016-12-12
  • Spring的初始化前中后詳細(xì)解讀

    Spring的初始化前中后詳細(xì)解讀

    這篇文章主要介紹了Spring的初始化前中后詳細(xì)解讀,Spring?框架是一個非常流行的?Java?框架,它提供了一種輕量級的、可擴(kuò)展的方式來構(gòu)建企業(yè)級應(yīng)用程序,在?Spring?的生命周期中,有三個重要的階段,即初始化前、初始化、初始化后,需要的朋友可以參考下
    2023-09-09

最新評論

高要市| 黄浦区| 育儿| 日照市| 洱源县| 苏尼特右旗| 新丰县| 乌审旗| 卓尼县| 长春市| 兖州市| 兴化市| 嘉荫县| 山阴县| 日喀则市| 永兴县| 桂平市| 枣强县| 贡嘎县| 漳平市| 苗栗市| 青河县| 阜宁县| 梅河口市| 大城县| 华亭县| 长阳| 小金县| 西吉县| 宜黄县| 五莲县| 英山县| 玉树县| 中超| 孝义市| 石狮市| 花垣县| 吉林省| 阜平县| 黄冈市| 敦化市|