当前位置: 首页 > article >正文

org.springframework.context.support.ApplicationListenerDetector 详细介绍

一,功能介绍

early post-processor for detecting inner beans as ApplicationListeners
早期的PostProcessor用来检测并处理内部(inner)bean作为 ApplicationListeners

BeanPostProcessor that detects beans which implement the ApplicationListener interface. This catches beans that can't reliably be detected by getBeanNamesForType and related operations which only work against top-level beans.

这个BeanPostProcessor 用于检测实现了 ApplicationListener 接口的 Bean,特别是那些无法通过 getBeanNamesForType 和相关操作检测到的内部 Bean,因为getBeanNamesForType 和相关操作 只针对 top-level beans。

言外之意就是这个 BeanPostProcessor 可以帮助你确保所有实现了 ApplicationListener 接口的 Bean 都能正确地处理应用事件,即使它们是内部 Bean 或非单例作用域的 Bean。

二,如何实现


/**
 * {@code BeanPostProcessor} that detects beans which implement the {@code ApplicationListener}
 * interface. This catches beans that can't reliably be detected by {@code getBeanNamesForType}
 * and related operations which only work against top-level beans.
 *
 * <p>With standard Java serialization, this post-processor won't get serialized as part of
 * {@code DisposableBeanAdapter} to begin with. However, with alternative serialization
 * mechanisms, {@code DisposableBeanAdapter.writeReplace} might not get used at all, so we
 * defensively mark this post-processor's field state as {@code transient}.
 *
 * @author Juergen Hoeller
 * @since 4.3.4
 */
class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {

	private static final Log logger = LogFactory.getLog(ApplicationListenerDetector.class);

	private final transient AbstractApplicationContext applicationContext;

	private final transient Map<String, Boolean> singletonNames = new ConcurrentHashMap<>(256);


	public ApplicationListenerDetector(AbstractApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}


	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		if (ApplicationListener.class.isAssignableFrom(beanType)) {
			this.singletonNames.put(beanName, beanDefinition.isSingleton());
		}
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (bean instanceof ApplicationListener) {
			// potentially not detected as a listener by getBeanNamesForType retrieval
			Boolean flag = this.singletonNames.get(beanName);
			if (Boolean.TRUE.equals(flag)) {
				// singleton bean (top-level or inner): register on the fly
				this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
			}
			else if (Boolean.FALSE.equals(flag)) {
				if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
					// inner bean with other scope - can't reliably process events
					logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
							"but is not reachable for event multicasting by its containing ApplicationContext " +
							"because it does not have singleton scope. Only top-level listener beans are allowed " +
							"to be of non-singleton scope.");
				}
				this.singletonNames.remove(beanName);
			}
		}
		return bean;
	}

	@Override
	public void postProcessBeforeDestruction(Object bean, String beanName) {
		if (bean instanceof ApplicationListener) {
			try {
				ApplicationEventMulticaster multicaster = this.applicationContext.getApplicationEventMulticaster();
				multicaster.removeApplicationListener((ApplicationListener<?>) bean);
				multicaster.removeApplicationListenerBean(beanName);
			}
			catch (IllegalStateException ex) {
				// ApplicationEventMulticaster not initialized yet - no need to remove a listener
			}
		}
	}

	@Override
	public boolean requiresDestruction(Object bean) {
		return (bean instanceof ApplicationListener);
	}


	@Override
	public boolean equals(@Nullable Object other) {
		return (this == other || (other instanceof ApplicationListenerDetector &&
				this.applicationContext == ((ApplicationListenerDetector) other).applicationContext));
	}

	@Override
	public int hashCode() {
		return ObjectUtils.nullSafeHashCode(this.applicationContext);
	}

}

        1.postProcessMergedBeanDefinition

        该bean的BeanDefination合并完了之后的,如果该bean的类是ApplicationListener子类,那么先用该bean的beanName标记该bean是不是单例,这个标记在后面bean实例化之后,判断是否要将这个ApplicationListener添加到org.springframework.context.support.AbstractApplicationContext#applicationListeners 和 org.springframework.context.support.AbstractApplicationContext#applicationEventMulticaster 中的时候用到。

这里的合并是指,当一个bean指定了parent的时候,需要把 parent 中定义的信息,合并到当前bean的BeanDefination中

        2.postProcessAfterInitialization

        该bean实例化之后,并且初始化之后,判断该bean是否是一个ApplicationListener类型的实例,如果不是不做处理,如果是ApplicationListener类型的实例再判断该bean是不是单例,如果是单例,就将其添加到org.springframework.context.support.AbstractApplicationContext#applicationListeners 和 org.springframework.context.support.AbstractApplicationContext#applicationEventMulticaster 以便在事件发生时能够通知到这些监听器。

之所以判断是不是单例,是因为如果一个 ApplicationListener 是非单例作用域的内部 Bean,应用上下文无法有效地管理和广播事件给这些 Bean,因为每次请求都会创建新的实例,而这些实例不在全局范围内注册。


http://www.kler.cn/a/399963.html

相关文章:

  • esp32c3开发板通过micropython的mqtt库连MQTT物联网消息服务器
  • WPF Gif图谱 如果隐藏的话会存在BUG
  • 计算机网络之会话层
  • 智能网页内容截图工具:AI助力内容提取与可视化
  • Python中的正则表达式教程
  • 基于Java和Vue实现的上门做饭系统上门做饭软件厨师上门app
  • Thinkphp-Laravel在线教育系统设计与实现us5uu
  • jenkins使用cli发行uni-app到h5
  • Spring Boot汽车资讯:速度与信息的融合
  • 【PSQLException: An I/O error occurred while sending to the backend.】
  • 网络基础概念与应用:深入理解计算机网络
  • Elastic 和 Red Hat:加速公共部门 AI 和机器学习计划
  • 第二十一章 Spring之假如让你来写AOP——Weaver(织入器)篇
  • 使用 PyTorch-BigGraph 构建和部署大规模图嵌入的完整教程
  • SError: (External) CUDA error(719), unspecified launch failure.
  • Clip结合Faiss+Flask简易版文搜图服务
  • 使用PSpice进行第一个电路的仿真
  • ACE之单例
  • 把一个对象序列化为字符串,再反序列化回来
  • cisco防火墙在内网通过外网域名进行访问的配置
  • 汽车与摩托车分类数据集
  • 【Flask+Gunicorn+Nginx】部署目标检测模型API完整解决方案
  • 【gitlab】gitlabrunner部署
  • 基于差分、粒子群算法下的TSP优化对比
  • YOLOv11融合针对小目标FFCA-YOPLO中的FEM模块及相关改进思路
  • Tailscale 自建 Derp 中转服务器