欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring源碼之事件監(jiān)聽機(jī)制(實(shí)現(xiàn)EventListener接口方式)

 更新時(shí)間:2024年08月13日 10:31:12   作者:it_lihongmin  
這篇文章主要介紹了Spring源碼之事件監(jiān)聽機(jī)制(實(shí)現(xiàn)EventListener接口方式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、Spring實(shí)現(xiàn)自定義事件的發(fā)布訂閱

Github地址為:https://github.com/kevin-lihongmin/designpattern/tree/master/src/main/java/com/kevin/designpattern/headfirst/observer/spring

1、事件定義

/**
 *  定義事件類型
 *
 * @author lihongmin
 * @date 2019/11/3 20:30
 */
public class OrderEvent extends ApplicationEvent {

    public OrderEvent(Object source) {
        super(source);
    }
}

2、事件監(jiān)聽(泛型)

/**
 *  訂單事件監(jiān)聽
 * @author lihongmin
 * @date 2019/11/3 20:33
 */
@Component
public class OrderEventListener implements ApplicationListener<OrderEvent> {

    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("我受到了一個(gè)事件:" + orderEvent.getSource());
    }
}

3、模擬事件發(fā)送

/**
 *  事件觸發(fā)模擬
 *
 *  我受到了一個(gè)事件:我發(fā)布了事件?。?!
 *  我執(zhí)行完畢了?。?!
 *
 * @author lihongmin
 * @date 2019/11/3 20:35
 */
@Controller
public class OrderEventController implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @GetMapping("publishOrderEvent")
    public String publishOrderEvent() {
        applicationContext.publishEvent(new OrderEvent("我發(fā)布了事件!?。?));
        System.out.println("我執(zhí)行完畢了?。?!");
        return "發(fā)送事件了!";
    }
}

4、啟動(dòng)項(xiàng)目,調(diào)用 127.0.0.1:8080/publishOrderEvent

我受到了一個(gè)事件:我發(fā)布了事件?。?!

我執(zhí)行完畢了?。。?/p>

總結(jié):事件發(fā)送非常的簡單,一個(gè)事件類型,一個(gè)監(jiān)聽,一個(gè)觸發(fā)機(jī)制。并且該事件為同步機(jī)制(后續(xù)在Spring Boot中可以方便切換為異步)。

二、Spring事件驅(qū)動(dòng)原理分析(Spring版本為5.1.7)

1、ApplicationContext委派ApplicationEventPublisher發(fā)送事件

我們調(diào)用的是 ApplicationContext的

publishEvent(new OrderEvent("我發(fā)布了事件?。。?)); 

查看ApplicationContext 結(jié)構(gòu),發(fā)現(xiàn)調(diào)用的是父類 ApplicationEventPublisher的接口

如下:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,
 HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    @Nullable
    String getId();

    String getApplicationName();

    String getDisplayName();

    long getStartupDate();

    @Nullable
    ApplicationContext getParent();

    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
public interface ApplicationEventPublisher {
    default void publishEvent(ApplicationEvent event) {
        this.publishEvent((Object)event);
    }

    void publishEvent(Object var1);
}

那么就是其子類 AbstractApplicationContext 實(shí)現(xiàn)的發(fā)送操作

public void publishEvent(Object event) {
        this.publishEvent(event, (ResolvableType)null);
    }

    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        Object applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent)event;
        } else {
            applicationEvent = new PayloadApplicationEvent(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
            }
        }

        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        } else {
            this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
        }

        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
            } else {
                this.parent.publishEvent(event);
            }
        }

    }

發(fā)現(xiàn)執(zhí)行到

getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType); 

那么其實(shí)這里算是一個(gè)委派模式了(個(gè)人認(rèn)為),spring容器將發(fā)送事件委派給 AbstractApplicationContext的ApplicationEventMulticaster applicationEventMulticaster對(duì)象。

2、ApplicationEventMutulcaster類型的確認(rèn)和初始化

不難發(fā)現(xiàn)(或者對(duì)Spring ApplicationContext比較熟悉的話)是項(xiàng)目啟動(dòng)時(shí),不同類型的ApplicationContext(如:ClassPathXmlApplicationContext)

在調(diào)用父類 AbstractApplicationContext的refresh方法(之前分析過是一個(gè)模板方法)時(shí), initApplicationEventMulticaster()

如下:

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
            this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        } else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }

    }

邏輯比較簡單,在BeanFactory中獲取名稱為 applicationEventMulticaster的Bean,當(dāng)然如果我們沒有自定義并且注冊(cè)為該名稱的Bean,肯定是獲取不到的。

那么會(huì)new一個(gè) SimpleApplicationEventMulticaster類型的bean注冊(cè)到容器中。

也就是說上面的getApplicationEventMulticaster()獲取到的就是SimpleApplicationEventMulticaster。

但是還需要注意使用的是有參數(shù)構(gòu)造進(jìn)行初始化,如下:

public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
    this.setBeanFactory(beanFactory);
}

在父類中實(shí)現(xiàn):

public void setBeanFactory(BeanFactory beanFactory) {
	this.beanFactory = beanFactory;
	if (beanFactory instanceof ConfigurableBeanFactory) {
		ConfigurableBeanFactory cbf = (ConfigurableBeanFactory)beanFactory;
		if (this.beanClassLoader == null) {
			this.beanClassLoader = cbf.getBeanClassLoader();
		}

		this.retrievalMutex = cbf.getSingletonMutex();
	}

}

獲取bean工廠中所以的所以單例對(duì)象放入屬性retrievalMutex 中,將類加載器也進(jìn)行賦值,后續(xù)會(huì)用到。

3、SimpleApplicationEventMulticaster的發(fā)送事件方法

public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        Iterator var4 = this.getApplicationListeners(event, type).iterator();

        while(var4.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var4.next();
            Executor executor = this.getTaskExecutor();
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                this.invokeListener(listener, event);
            }
        }

    }

分析一下這個(gè)方法:

  • 1)、獲取或確認(rèn) ResolvableType 類型
  • 2)、根據(jù)事件對(duì)象和ResolvableType 類型,獲取訂閱者列表
  • 3)、發(fā)現(xiàn)如果 SimpleApplicationEventMulticaster對(duì)象的線程池屬性 Executor taskExecutor不為null則異步執(zhí)行監(jiān)聽方法。但是我們看到的是自己new了一個(gè)對(duì)象,所以如果想 事件監(jiān)聽使用線程池異步執(zhí)行的話(自己想到應(yīng)該可以這樣玩,自己比較喜歡自定義線程參數(shù),心里有數(shù),當(dāng)前一般還會(huì)設(shè)置線程池前綴名稱):
@Component
public class DesignpatternApplication implements BeanFactoryAware {

	private BeanFactory beanFactory;
	
	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}
	
	@Bean("APPLICATION_EVENT_MULTICASTER_BEAN_NAME")
	public SimpleApplicationEventMulticaster init() {
		ThreadPoolExecutor MulticasterExecutor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS,
				new LinkedBlockingDeque<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
		SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
		multicaster.setTaskExecutor(MulticasterExecutor);
		multicaster.setBeanFactory(beanFactory);
		return multicaster;
	}
}
  • 4)、最后肯定是invokeListener(listener, event);

4、ResolvableType類型確認(rèn)

首先我們傳入的eventType是null,所以先根據(jù)我們傳入的對(duì)象調(diào)用resolveDefaultEventType方法

如下:

private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
    return ResolvableType.forInstance(event);
}

再調(diào)用,肯定OrderEvent肯定沒有實(shí)現(xiàn)ResolvableTypeProvider接口:

public static ResolvableType forInstance(Object instance) {
	Assert.notNull(instance, "Instance must not be null");
	if (instance instanceof ResolvableTypeProvider) {
		ResolvableType type = ((ResolvableTypeProvider) instance).getResolvableType();
		if (type != null) {
			return type;
		}
	}
	return ResolvableType.forClass(instance.getClass());
}

再調(diào)用:

public static ResolvableType forClass(@Nullable Class<?> clazz) {
	return new ResolvableType(clazz);
}

所以我們或者到了一個(gè)新創(chuàng)建的 ResolvableType 對(duì)象,對(duì)象的clazz字段為我們的 OrderEvent。

為什么追這么深,是因?yàn)橄旅婢褪歉鶕?jù)類型來獲取監(jiān)聽器的。

5、獲取所有的監(jiān)聽列表,并且看看是怎么做到監(jiān)聽泛型類型

protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
        Object source = event.getSource();
        Class<?> sourceType = source != null ? source.getClass() : null;
        AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
        AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
        if (retriever != null) {
            return retriever.getApplicationListeners();
        } else if (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) {
            Object var7 = this.retrievalMutex;
            synchronized(this.retrievalMutex) {
                retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
                if (retriever != null) {
                    return retriever.getApplicationListeners();
                } else {
                    retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
                    Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever);
                    this.retrieverCache.put(cacheKey, retriever);
                    return listeners;
                }
            }
        } else {
            return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null);
        }
    }

在自己的 ConcurrentHashMap類型的retrieverCache緩存中獲取,key是根據(jù) OrderEvent類型和我發(fā)送的數(shù)據(jù)源(當(dāng)前為String類型)如下:

  • Map的key:
private static final class ListenerCacheKey implements 
Comparable<AbstractApplicationEventMulticaster.ListenerCacheKey> {
    private final ResolvableType eventType;
    @Nullable
    private final Class<?> sourceType;

    // .....
}
  • Map的value類型:
private class ListenerRetriever {
    public final Set<ApplicationListener<?>> applicationListeners = 
        new LinkedHashSet();
    public final Set<String> applicationListenerBeans = new LinkedHashSet();
    private final boolean preFiltered;
}

很清楚的結(jié)構(gòu),兩個(gè)LinkedHashSet, 就是為了保證兩個(gè)Set個(gè)數(shù)相同,并且順序一一對(duì)應(yīng)。用于存放當(dāng)前的監(jiān)聽對(duì)象和監(jiān)聽的類型。

當(dāng)前的緩存是在AbstractApplicationContext的refresh的registerBeanPostProcessors(注冊(cè)所有的BeanPostProcess),的最后一步,注冊(cè)了ApplicationListenerDetector類型。

并且在refresh的最后會(huì)將所有懶加載的Bean都初始化,則會(huì)將所有的實(shí)現(xiàn)了該接口的Bean放入容器中。

則重點(diǎn)是 retrieveApplicationListeners方法,比較長:

private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.ListenerRetriever retriever) {
	List<ApplicationListener<?>> allListeners = new ArrayList();
	Object var7 = this.retrievalMutex;
	LinkedHashSet listeners;
	LinkedHashSet listenerBeans;
	synchronized(this.retrievalMutex) {
		listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
		listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
	}

	Iterator var14 = listeners.iterator();

	while(var14.hasNext()) {
		ApplicationListener<?> listener = (ApplicationListener)var14.next();
		if (this.supportsEvent(listener, eventType, sourceType)) {
			if (retriever != null) {
				retriever.applicationListeners.add(listener);
			}

			allListeners.add(listener);
		}
	}

	if (!listenerBeans.isEmpty()) {
		BeanFactory beanFactory = this.getBeanFactory();
		Iterator var16 = listenerBeans.iterator();

		while(var16.hasNext()) {
			String listenerBeanName = (String)var16.next();

			try {
				Class<?> listenerType = beanFactory.getType(listenerBeanName);
				if (listenerType == null || this.supportsEvent(listenerType, eventType)) {
					ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
					if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
						if (retriever != null) {
							if (beanFactory.isSingleton(listenerBeanName)) {
								retriever.applicationListeners.add(listener);
							} else {
								retriever.applicationListenerBeans.add(listenerBeanName);
							}
						}

						allListeners.add(listener);
					}
				}
			} catch (NoSuchBeanDefinitionException var13) {
				;
			}
		}
	}

	AnnotationAwareOrderComparator.sort(allListeners);
	if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
		retriever.applicationListeners.clear();
		retriever.applicationListeners.addAll(allListeners);
	}

	return allListeners;
}

分析該方法,上面鎖住的是 retrievalMutex對(duì)象,現(xiàn)在又是同步鎖該對(duì)象。

為了保證LinkedHashSet中的值不會(huì)亂(monitor enter兩次exit兩次),去緩存中的每個(gè)查看每個(gè)監(jiān)聽器是否是對(duì)象的類型,檢查了監(jiān)聽器的泛型對(duì)象和事件源類型。

6、根據(jù)監(jiān)聽列表,循環(huán)調(diào)用(同步或異步)

我們實(shí)現(xiàn)的 onApplicationEvent(OrderEvent orderEvent)方法

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
	ErrorHandler errorHandler = this.getErrorHandler();
	if (errorHandler != null) {
		try {
			this.doInvokeListener(listener, event);
		} catch (Throwable var5) {
			errorHandler.handleError(var5);
		}
	} else {
		this.doInvokeListener(listener, event);
	}

}

所以 ErrorHandler想在這里處理,則需要在該對(duì)象中創(chuàng)建該異常處理器(可以有很多中方式處理,利用bean的生命周期,這是一個(gè)很好的擴(kuò)展點(diǎn),后續(xù)可以去實(shí)現(xiàn)),繼續(xù) doInvokeListener方法

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
	try {
		listener.onApplicationEvent(event);
	} catch (ClassCastException var6) {
		String msg = var6.getMessage();
		if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
			throw var6;
		}

		Log logger = LogFactory.getLog(this.getClass());
		if (logger.isTraceEnabled()) {
			logger.trace("Non-matching event type for listener: " + listener, var6);
		}
	}

}

最后看見 listener.onApplicationEvent(event);

it is over?。?!

總結(jié)

1、ApplicationContext發(fā)送事件是委托給了一個(gè) Spring容器在refresh時(shí)初始化的SimpleApplicationEventMulticaster bean(由于沒有初始化內(nèi)部線程池對(duì)象,所以事件是同步發(fā)送的)。

2、發(fā)送前先獲取事件的ResolvableType類型(當(dāng)前為OrderEvent clazz)和事件源類型(當(dāng)前為String)

3、獲取監(jiān)聽者列表。 先去自己Bean內(nèi)部先查詢緩存,否則從BeanFactory中獲取所有單利bean進(jìn)行匹配(再放入緩存ConturrentHashMap)。

4、監(jiān)聽者列表循環(huán)(同步或異步)地調(diào)用我們自己寫的監(jiān)聽方法OnApplicationEvent。

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

相關(guān)文章

  • 利用EasyPOI實(shí)現(xiàn)多sheet和列數(shù)的動(dòng)態(tài)生成

    利用EasyPOI實(shí)現(xiàn)多sheet和列數(shù)的動(dòng)態(tài)生成

    EasyPoi功能如同名字,主打的功能就是容易,讓一個(gè)沒見接觸過poi的人員就可以方便的寫出Excel導(dǎo)出,Excel導(dǎo)入等功能,本文主要來講講如何利用EasyPOI實(shí)現(xiàn)多sheet和列數(shù)的動(dòng)態(tài)生成,需要的可以了解下
    2025-03-03
  • SpringBoot Actuator未授權(quán)訪問漏洞的排查和解決方法

    SpringBoot Actuator未授權(quán)訪問漏洞的排查和解決方法

    Spring Boot Actuator 是開發(fā)和管理生產(chǎn)級(jí) Spring Boot 應(yīng)用程序的重要工具,它可以幫助你確保應(yīng)用程序的穩(wěn)定性和性能,本文給大家介紹了SpringBoot Actuator未授權(quán)訪問漏洞的排查和解決方法,需要的朋友可以參考下
    2024-05-05
  • Java中Date日期類的使用方法示例詳解

    Java中Date日期類的使用方法示例詳解

    這篇文章主要介紹了Java中Date日期類的使用方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • SpringBoot中的配置類(@Configuration)

    SpringBoot中的配置類(@Configuration)

    這篇文章主要介紹了SpringBoot中的配置類(@Configuration),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Spring整合MyBatis圖示過程解析

    Spring整合MyBatis圖示過程解析

    這篇文章主要介紹了Spring整合MyBatis圖示過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • springBoot詳解集成Swagger流程

    springBoot詳解集成Swagger流程

    Swagger是一個(gè)規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化?Restful?風(fēng)格的?Web?服務(wù)??傮w目標(biāo)是使客戶端和文件系統(tǒng)作為服務(wù)器以同樣的速度來更新。文件的方法、參數(shù)和模型緊密集成到服務(wù)器端的代碼,允許API來始終保持同步
    2022-06-06
  • Spring Cache手動(dòng)清理Redis緩存

    Spring Cache手動(dòng)清理Redis緩存

    這篇文章主要介紹了Spring Cache手動(dòng)清理Redis緩存,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java仿12306圖片驗(yàn)證碼

    Java仿12306圖片驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了Java仿12306的圖片驗(yàn)證碼的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-04-04
  • Java強(qiáng)制轉(zhuǎn)化示例代碼詳解

    Java強(qiáng)制轉(zhuǎn)化示例代碼詳解

    這篇文章主要介紹了Java編程語言中的類型轉(zhuǎn)換,包括基本類型之間的強(qiáng)制類型轉(zhuǎn)換和引用類型的強(qiáng)制類型轉(zhuǎn)換,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-03-03
  • java基于C/S模式實(shí)現(xiàn)聊天程序(客戶端)

    java基于C/S模式實(shí)現(xiàn)聊天程序(客戶端)

    這篇文章主要為大家詳細(xì)介紹了java基于C/S模式實(shí)現(xiàn)聊天程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01

最新評(píng)論