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

news/2024/11/19 13:10:31/

一,功能介绍

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。

二,如何实现

java">
/*** {@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;}@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {if (ApplicationListener.class.isAssignableFrom(beanType)) {this.singletonNames.put(beanName, beanDefinition.isSingleton());}}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {if (bean instanceof ApplicationListener) {// potentially not detected as a listener by getBeanNamesForType retrievalBoolean flag = this.singletonNames.get(beanName);if (Boolean.TRUE.equals(flag)) {// singleton bean (top-level or inner): register on the flythis.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 eventslogger.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;}@Overridepublic 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}}}@Overridepublic boolean requiresDestruction(Object bean) {return (bean instanceof ApplicationListener);}@Overridepublic boolean equals(@Nullable Object other) {return (this == other || (other instanceof ApplicationListenerDetector &&this.applicationContext == ((ApplicationListenerDetector) other).applicationContext));}@Overridepublic 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.ppmy.cn/news/1548240.html

相关文章

2. kafka 生产者

一. 生产者消息发送流程 在消息发送的过程中&#xff0c;涉及到了两个线程&#xff1a;main线程和Sender线程。Producer发送的消息会分别经过Interceptors(拦截器)&#xff0c;Serializer(序列化器)&#xff0c;Partitioner(分区器)最终到达RecordAccumulator&#xff0c;Recor…

删除k8s 或者docker运行失败的脚本

vi delete_exited_containers.sh#!/bin/bash# 列出所有停止的容器并存储到数组 list_exited_containers() {echo -e "\nStopped containers:"containers()# 获取停止的容器信息并存入数组while IFS read -r line; docontainers("$line")done < <(do…

31-Shard Allocation Awareness(机架感知)

同一机器上&#xff0c;部署多个es节点&#xff0c;防止副本和主分片分配到同一机器上 例如&#xff1a;es节点a、b、c部署在01机器上&#xff0c;节点d、e、f部署在02机器上 es2.4版本配置 a、b、c节点yaml配置&#xff1a;node.rack: aaa d、e、f节点yaml配置&#xff1a…

FlutterCacheManager组件的用法

文章目录 1. 概念介绍2. 使用方法2.1 调用接口2.2 管理缓冲3. 示例代码4. 内容总结我们在上一章回中介绍了"CachedNetworkImage组件"相关的内容,本章回中将介绍FlutterCacheManager组件.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章回中介绍的内容…

【数据结构】`unordered_map` 和 `unordered_set` 的底层原理

unordered_map 和 unordered_set 是 C 标准库中的两个容器&#xff0c;它们被广泛应用于需要快速查找的场景中。它们的查找、插入和删除的平均时间复杂度都是 O(1)&#xff0c;这也是它们的一个重要特性。本文将详细介绍 unordered_map 和 unordered_set 的底层原理&#xff0c…

QT QLabel双击事件

新建类&#xff1a; DoubleClickLabel .h #pragma once#include <QLabel>class DoubleClickLabel : public QLabel {Q_OBJECTpublic:DoubleClickLabel(QWidget *parent);~DoubleClickLabel(); signals:void doubleClicked();protected: //这里重写双击事件virtual v…

学习rust语言宏之macro_rules!

学习rust语言&#xff0c;必然不可避免要了解和熟悉宏。rust语言的宏功能非常强大&#xff0c;通过合理的编写利用宏&#xff0c;可以简化程序代码&#xff0c;也少写很多代码。今天我们先从宏的基本编写方法macro_rules开始&#xff1a; 1&#xff0c;格式 macro_rules! $na…

[C++]:C++11(一)

1. 统一列表初始化 1.1 C11 之前的初始化方式 在 C11 标准中&#xff0c;引入了一个非常实用且强大的特性——统一列表初始化&#xff08;Uniform Initialization&#xff09;&#xff0c;它为我们在初始化各种类型的对象时提供了一种统一且方便的语法形式&#xff0c;极大地…