SpringBoot监听器模式怎么实现

发布时间:2022-07-15 13:55:21 作者:iii
来源:亿速云 阅读:211

本篇内容介绍了“SpringBoot监听器模式怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

我们来以应用启动事件:ApplicationStartingEvent为例来进行说明:

以启动类的SpringApplication.run方法为入口,跟进SpringApplication的两个同名方法后,我们会看到主要的run方法,方法比较长,在这里只贴出与监听器密切相关的关键的部分:

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();

我们跟进这个starting方法,方法的内容如下:

void starting() {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.starting();
	}
}

这里的listeners已经在getRunListeners方法中完成了加载,加载原理类似于系统初始化器,关于系统初始化器的加载可以参考SpringBoot深入浅出分析初始化器

starting方法逻辑很简单,就是调用SpringApplicationRunListener的starting方法。下面继续分析这个starting方法:

我们进入了EventPublishingRunListener类(SpringApplicationRunListener 的实现类)的starting方法:

	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}

这里就使用了广播器,来广播新的ApplicationStartingEvent事件。

我们跟进这个multicastEvent方法:

	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

继续看同名的方法multicastEvent:

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

这里的ResolvableType 是对event做了包装,我们不去关注;由于我们没有创建线程池,所以executor是空的。我们重点关注两个部分:

1、getApplicationListeners --> 获取所有关注此事件的监听器(※);

2、invokeListener --> 激活监听器;

getApplicationListeners (AbstractApplicationEventMulticaster类中)方法,代码如下:

	protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
		Object source = event.getSource();
		Class<?> sourceType = (source != null ? source.getClass() : null);
		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
		// Quick check for existing entry on ConcurrentHashMap...
		ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
		if (retriever != null) {
			return retriever.getApplicationListeners();
		}
		if (this.beanClassLoader == null ||
				(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
						(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
			// Fully synchronized building and caching of a ListenerRetriever
			synchronized (this.retrievalMutex) {
				retriever = this.retrieverCache.get(cacheKey);
				if (retriever != null) {
					return retriever.getApplicationListeners();
				}
				retriever = new ListenerRetriever(true);
				Collection<ApplicationListener<?>> listeners =
						retrieveApplicationListeners(eventType, sourceType, retriever);
				this.retrieverCache.put(cacheKey, retriever);
				return listeners;
			}
		}
		else {
			// No ListenerRetriever caching -> no synchronization necessary
			return retrieveApplicationListeners(eventType, sourceType, null);
		}
	}

入参中的event就是ApplicationStartingEvent,sourceType是org.springframework.boot.SpringApplication类。ListenerRetriever类型本人将其视作是一个保存监听器的容器。

可以看出,程序首先在缓存里面寻找ListenerRetriever类型的retriever,如果没有找到,加锁再从缓存里面找一次。这里我们缓存里是没有内容的,所以都不会返回。

接下来调用了retrieveApplicationListeners方法,来遍历所有的监听器。retrieveApplicationListeners方法比较长,我们重点关注下supportsEvent(listener, eventType, sourceType)方法,该方法用来判断是否此监听器关注该事件,过程主要包括,判断此类型是否是GenericApplicationListener类型,如果不是,则构造一个代理,代理的目的是,通过泛型解析,最终获得监听器所感兴趣的事件。

如果经过判断,监听器对该事件是感兴趣的,则此监听器会被加入监听器列表中。

	protected boolean supportsEvent(
			ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
		GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
				(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
		return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
	}

当某个事件所有的监听器被收集完毕后,multicastEvent(SimpleApplicationEventMulticaster类)方法会对事件进行传播。即调用监听器的通用触发接口方法:listener.onApplicationEvent(event);这样,就完成了这个事件的传播。

“SpringBoot监听器模式怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

推荐阅读:
  1. javaweb监听器接口-观察者模式
  2. Springboot项目监听器失效问题解决

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot

上一篇:react中怎么应用SOLID原则

下一篇:C语言结构体,枚举,联合体如何使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》