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

Spring事件監(jiān)聽器ApplicationListener的使用與原理分析

 更新時(shí)間:2025年11月19日 09:44:19   作者:n***6327  
文章介紹了Spring中的事件監(jiān)聽器和事件發(fā)布機(jī)制,包括內(nèi)置事件的使用和自定義事件的創(chuàng)建與發(fā)布,以及如何使用@EventListener注解進(jìn)行事件監(jiān)聽,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧

ApplicationEvent以及Listener是Spring為我們提供的一個(gè)事件監(jiān)聽、訂閱的實(shí)現(xiàn),內(nèi)部實(shí)現(xiàn)原理是觀察者設(shè)計(jì)模式,設(shè)計(jì)初衷也是為了系統(tǒng)業(yè)務(wù)邏輯之間的解耦,提高可擴(kuò)展性以及可維護(hù)性。事件發(fā)布者并不需要考慮誰去監(jiān)聽,監(jiān)聽具體的實(shí)現(xiàn)內(nèi)容是什么,發(fā)布者的工作只是為了發(fā)布事件而已。

Spring提供的內(nèi)置事件:

  • ContextRefreshedEvent:容器刷新事件
  • ContextStartedEvent:容器啟動(dòng)事件
  • ContextStoppedEvent:容器停止事件
  • ContextClosedEvent:容器關(guān)閉事件

如何使用

監(jiān)聽容器的刷新事件

自定義一個(gè)ApplicationListener,指定監(jiān)聽的事件類型ContextRefreshedEvent:

package com.morris.spring.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		System.out.println("context refresh");
	}
}

注入到容器中:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ContextRefreshedListener.class);
applicationContext.refresh(); 

applicationContext.refresh()內(nèi)部會(huì)發(fā)送容器刷新的事件。

自定義事件

自定義的事件需要繼承ApplicationEvent:

package com.morris.spring.event;
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent {
	public CustomEvent(Object source) {
		super(source);
	}
}

監(jiān)聽的時(shí)候使用ApplicationEvent的子類CustomEvent:

package com.morris.spring.listener;
import com.morris.spring.event.CustomEvent;
import org.springframework.context.ApplicationListener;
public class CustomEventListener implements ApplicationListener<CustomEvent> {
	@Override
	public void onApplicationEvent(CustomEvent event) {
		System.out.println("custom event: " + event.getSource());
	}
}

可以使用AnnotationConfigApplicationContext發(fā)布事件:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(CustomEventListener.class);
applicationContext.refresh();
applicationContext.publishEvent(new CustomEvent("custom event"));

可以向bean中注入一個(gè)ApplicationEventPublisher來發(fā)布事件:

package com.morris.spring.service;
import com.morris.spring.event.CustomEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
public class CustomEventService {
	@Autowired
	private ApplicationEventPublisher applicationEventPublisher;
	public void publishEvent() {
		applicationEventPublisher.publishEvent(new CustomEvent("自定義事件"));
	}
}

可以通過實(shí)現(xiàn)ApplicationEventPublisherAware接口注入ApplicationEventPublisher來發(fā)布事件:

package com.morris.spring.service;
import com.morris.spring.event.CustomEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
public class CustomEventService2 implements ApplicationEventPublisherAware {
	private ApplicationEventPublisher applicationEventPublisher;
	public void publishEvent() {
		applicationEventPublisher.publishEvent(new CustomEvent("自定義事件"));
	}
	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.applicationEventPublisher = applicationEventPublisher;
	}
}

由于ApplicationContext實(shí)現(xiàn)了ApplicationEventPublisher接口,也可以直接注入ApplicationContext來發(fā)布事件。

使用@EventListener監(jiān)聽事件

在監(jiān)聽事件時(shí),由于類需要實(shí)現(xiàn)ApplicationListener接口,對(duì)代碼有很大的侵入性,可以使用@EventListener注解隨時(shí)隨地監(jiān)聽事件,這樣一個(gè)Service中可以監(jiān)聽多個(gè)事件:

package com.morris.spring.listener;
import com.morris.spring.event.CustomEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
public class CustomEventListener2 {
	@EventListener
	public void listenContextRefreshedEvent(ContextRefreshedEvent event) {
		System.out.println("context refresh");
	}
	@EventListener
	public void listenCustomEvent(CustomEvent event) {
		System.out.println("custom event: " + event.getSource());
	}
}

還可以在@EventListener注解上指定監(jiān)聽的事件類型:

package com.morris.spring.listener;
import com.morris.spring.event.CustomEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
public class CustomEventListener3 {
	@EventListener({ContextRefreshedEvent.class, CustomEvent.class})
	public void listenEvent(ApplicationEvent event) {
		System.out.println(event);
	}
}

異步發(fā)送消息

spring消息的發(fā)送默認(rèn)都是同步的,如果要異步發(fā)送消息,首先要在配置類上開啟異步功能@EnableAsync:

package com.morris.spring.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync // 開啟異步
public class EventListenerConfig {
}

在監(jiān)聽的方法上加上@Async:

package com.morris.spring.listener;
import com.morris.spring.event.CustomEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
@Slf4j
public class AsyncCustomEventListener {
	@EventListener({ContextRefreshedEvent.class, CustomEvent.class})
	@Async // 異步
	public void listenEvent(ApplicationEvent event) {
		log.info("receive event: {}", event);
	}
}

也可以自定義執(zhí)行異步消息的線程池(默認(rèn)就是SimpleAsyncTaskExecutor):

@Bean
public TaskExecutor executor() {
	return new SimpleAsyncTaskExecutor("eventListen-");
}

異步消息只是借用spring的異步執(zhí)行機(jī)制,在方法上加上@Async注解,方法都會(huì)異步執(zhí)行。

ApplicationListener原理分析

發(fā)布消息的入口

發(fā)布消息入口:
org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)

public void publishEvent(ApplicationEvent event) {
    publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
...
        /**
         * @see SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
         */
        // 發(fā)布消息
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }
... ...
}

然后調(diào)用SimpleApplicationEventMulticaster來進(jìn)行廣播消息:

// org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 如果有線程池,將會(huì)異步執(zhí)行
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            doInvokeListener(listener, event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
    else {
        // ApplicationListener.調(diào)用onApplicationEvent
        doInvokeListener(listener, event);
    }
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        String msg = ex.getMessage();
        if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            // -> let's suppress the exception and just log a debug message.
            Log logger = LogFactory.getLog(getClass());
            if (logger.isTraceEnabled()) {
                logger.trace("Non-matching event type for listener: " + listener, ex);
            }
        }
        else {
            throw ex;
        }
    }
}

何時(shí)注入SimpleApplicationEventMulticaster

從上面的源碼可以發(fā)現(xiàn)spring是通過SimpleApplicationEventMulticaster事件多播器來發(fā)布消息的,那么這個(gè)類是何時(shí)注入的呢?容器refresh()時(shí)。

org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster

protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
		this.applicationEventMulticaster =
				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
		}
	}
	else {
		// 直接new,然后放入到spring一級(jí)緩存中
		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		if (logger.isTraceEnabled()) {
			logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
					"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
		}
	}
}

何時(shí)注入ApplicationListener

spring在發(fā)布消息時(shí),會(huì)從SimpleApplicationEventMulticaster中拿出所有的ApplicationListener,那么這些ApplicationListener何時(shí)被注入的呢?容器refresh()時(shí)。

org.springframework.context.support.AbstractApplicationContext#registerListeners

protected void registerListeners() {
	// Register statically specified listeners first.
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}
	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String listenerBeanName : listenerBeanNames) {
		// 添加到SimpleApplicationEventMulticaster中
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}
	// Publish early application events now that we finally have a multicaster...
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}

@EventListener的原理

@EventListener注解的功能是通過EventListenerMethodProcessor來實(shí)現(xiàn)的,EventListenerMethodProcessor這個(gè)類在AnnotationConfigApplicationContext的構(gòu)造方法中被注入。

EventListenerMethodProcessor主要實(shí)現(xiàn)了兩個(gè)接口:SmartInitializingSingleton和BeanFactoryPostProcessor。

先來看看BeanFactoryPostProcessor的postProcessBeanFactory(),這個(gè)方法主要是保存beanFactory和eventListenerFactories,后面的方法將會(huì)使用到:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 保存beanFactory
    this.beanFactory = beanFactory;
    /**
     * EventListenerFactory[DefaultEventListenerFactory]在何處被注入?
     * @see AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
     */
    Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
    List<EventListenerFactory> factories = new ArrayList<>(beans.values());
    AnnotationAwareOrderComparator.sort(factories);
    // 保存eventListenerFactories
    this.eventListenerFactories = factories;
}

再來看看SmartInitializingSingleton的afterSingletonsInstantiated()方法,這個(gè)方法會(huì)在所有的bean初始化完后執(zhí)行。

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)) {
			// 目標(biāo)類的類型
			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 {
					// 處理目標(biāo)對(duì)象
					processBean(beanName, type);
				}
				catch (Throwable ex) {
					throw new BeanInitializationException("Failed to process @EventListener " +
							"annotation on bean with name '" + beanName + "'", ex);
				}
			}
		}
	}
}
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 {
			// 獲得類中所有的帶有@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)) {
			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) {
					if (factory.supportsMethod(method)) {
						Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
						// 使用factory創(chuàng)建一個(gè)ApplicationListener
						ApplicationListener<?> applicationListener =
								factory.createApplicationListener(beanName, targetType, methodToUse);
						if (applicationListener instanceof ApplicationListenerMethodAdapter) {
							((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
						}
						// 將ApplicationListener添加到Spring容器中
						context.addApplicationListener(applicationListener);
						break;
					}
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
						beanName + "': " + annotatedMethods);
			}
		}
	}
}

SpringBoot中的事件

SpringBoot在啟動(dòng)時(shí)會(huì)按以下順序發(fā)送消息:

  1. ApplicationStartingEvent:在運(yùn)行開始時(shí)發(fā)送 ,但在進(jìn)行任何處理之前(偵聽器和初始化程序的注冊(cè)除外)發(fā)送
  2. ApplicationEnvironmentPreparedEvent:當(dāng)被發(fā)送Environment到中已知的上下文中使用,但是在創(chuàng)建上下文之前
  3. ApplicationContextInitializedEvent:在ApplicationContext準(zhǔn)備好且已調(diào)用ApplicationContextInitializers之后但任何bean定義未加載之前發(fā)送
  4. ApplicationPreparedEvent:在刷新開始之前但在加載bean定義之后發(fā)送
  5. ApplicationStartedEvent:上下文已被刷新后發(fā)送,但是任何應(yīng)用程序和命令行都被調(diào)用前
  6. ApplicationReadyEvent:在所有的命令行應(yīng)用啟動(dòng)后發(fā)送此事件,可以處理請(qǐng)求
  7. ApplicationFailedEvent:在啟動(dòng)時(shí)異常發(fā)送

到此這篇關(guān)于Spring事件監(jiān)聽器ApplicationListener的使用與源碼分析的文章就介紹到這了,更多相關(guān)Spring ApplicationListener使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 被kafka-client和springkafka版本坑到自閉及解決

    被kafka-client和springkafka版本坑到自閉及解決

    這篇文章主要介紹了被kafka-client和springkafka版本坑到自閉及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java多線程之線程狀態(tài)的遷移詳解

    Java多線程之線程狀態(tài)的遷移詳解

    線程狀態(tài)遷移,又常被稱作線程的生命周期,指的是線程從創(chuàng)建到終結(jié)需要經(jīng)歷哪些狀態(tài),什么情況下會(huì)出現(xiàn)哪些狀態(tài).線程的狀態(tài)直接關(guān)系著并發(fā)編程的各種問題,本文就線程的狀態(tài)遷移做一初步探討,并總結(jié)在何種情況下會(huì)出現(xiàn)這些狀態(tài),需要的朋友可以參考下
    2021-06-06
  • Java內(nèi)省實(shí)例解析

    Java內(nèi)省實(shí)例解析

    這篇文章主要介紹了Java內(nèi)省實(shí)例解析,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • 利用maven deploy上傳本地jar至私服的方法

    利用maven deploy上傳本地jar至私服的方法

    這篇文章主要介紹了利用maven deploy上傳本地jar至私服的方法,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • SpringBoot遠(yuǎn)程訪問redis服務(wù)器問題剖析

    SpringBoot遠(yuǎn)程訪問redis服務(wù)器問題剖析

    使用了SpringBoot的項(xiàng)目,在遠(yuǎn)程連接Redis服務(wù)器時(shí),會(huì)遇倒一些小問題,下面通過本文給大家全面解析SpringBoot遠(yuǎn)程訪問redis服務(wù)器問題,需要的朋友參考下吧
    2017-04-04
  • 五分鐘帶你學(xué)會(huì)用java解析json字符串

    五分鐘帶你學(xué)會(huì)用java解析json字符串

    這篇文章主要給大家介紹了關(guān)于用java解析json字符串的相關(guān)資料,JSON是一種輕量級(jí)的、基于文本的、與語言無關(guān)的數(shù)據(jù)交換格式,易于人和機(jī)器讀寫,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Java如何實(shí)現(xiàn)樹的同構(gòu)?

    Java如何實(shí)現(xiàn)樹的同構(gòu)?

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識(shí),文章圍繞著Java如何實(shí)現(xiàn)樹的同構(gòu)展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 詳細(xì)介紹Java阿里云的短信驗(yàn)證碼實(shí)現(xiàn)

    詳細(xì)介紹Java阿里云的短信驗(yàn)證碼實(shí)現(xiàn)

    這篇文章主要介紹了詳細(xì)介紹Java阿里云的短信驗(yàn)證碼實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • java中TESTful架構(gòu)原理分析

    java中TESTful架構(gòu)原理分析

    這篇文章主要介紹了對(duì)java架構(gòu)中TESTful架構(gòu)原理進(jìn)行了詳細(xì)的原理分析,有需要的朋友可以借鑒參考下,希望可以有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-09-09
  • 關(guān)于BindingResult的使用總結(jié)及注意事項(xiàng)

    關(guān)于BindingResult的使用總結(jié)及注意事項(xiàng)

    這篇文章主要介紹了關(guān)于BindingResult的使用總結(jié)及注意事項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評(píng)論

景泰县| 吉木萨尔县| 金溪县| 获嘉县| 安塞县| 大新县| 金湖县| 伊川县| 凉城县| 夏邑县| 文成县| 凌源市| 安岳县| 正安县| 墨江| 电白县| 古田县| 德令哈市| 封开县| 拉萨市| 孟津县| 保亭| 兴仁县| 灯塔市| 启东市| 墨脱县| 神池县| 民丰县| 东城区| 修水县| 齐河县| 石渠县| 玛曲县| 岢岚县| 平遥县| 慈溪市| 南康市| 平陆县| 综艺| 贺兰县| 南川市|