Spring中refresh分析之registerListeners方法详解

简介: Spring中refresh分析之registerListeners方法详解

们分析过onRefresh后,本文分析registerListeners方法。


顾名思义,注册监听器。将会获取AbstractApplicationContext的applicationListeners和容器中的ApplicationListener进行注册,最后会尝试将earlyApplicationEvents广播出去。

protected void registerListeners() {
  // Register statically specified listeners first.
  //获取的是成员applicationListeners
  for (ApplicationListener<?> listener : getApplicationListeners()) {
  // 获取SimpleApplicationEventMulticaster触发其方法
    getApplicationEventMulticaster().addApplicationListener(listener);
  }
  // Do not initialize FactoryBeans here: We need to leave all regular beans
  // uninitialized to let post-processors apply to them!
  // 从容器中获取ApplicationListener
  String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
  for (String listenerBeanName : listenerBeanNames) {
    // 获取SimpleApplicationEventMulticaster触发其方法-这里放的是beanName
    getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  }
  // Publish early application events now that we finally have a multicaster...
  // 发布早期事件,本文这里为空
  Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
  //设置为null,这个很重要
  this.earlyApplicationEvents = null;
  if (earlyEventsToProcess != null) {
  // 如果早期/渴望的事件存在,则将其广播出去
    for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
      getApplicationEventMulticaster().multicastEvent(earlyEvent);
    }
  }
}

方法逻辑梳理如下:


获取AbstractApplicationContext的成员监听器然后遍历进行注册;

从容器中获取ApplicationListener然后进行遍历记录监听器名称放到this.defaultRetriever.applicationListenerBeans;

earlyApplicationEvents赋予earlyEventsToProcess 然后重新将置为null。如果earlyEventsToProcess不为空则进行遍历挨个进行事件广播。

这里getApplicationListeners()获取的applicationListeners 是AbstractApplicationContext的成员private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();。这些监听器是在refresh方法前的prepareContext方法中注册进来的。


earlyApplicationEvents我们在哪里看到过呢?仍然是prepareRefresh方法中,对其进行了初始化是一个空的LinkedHashSet。


通过应用上下文广播事件时,如果事件广播器还没有实例化好,那么事件会被存放在earlyApplicationEvents中。当事件广播器实例化好之后,earlyApplicationEvents会被指向null,其维护的早期事件会被广播出去。

addApplicationListener

我们继续看SimpleApplicationEventMulticasteraddApplicationListener方法,看是如何对监听器进行注册的。

@Override
public void addApplicationListener(ApplicationListener<?> listener) {
  synchronized (this.retrievalMutex) {
    // Explicitly remove target for a proxy, if registered already,
    // in order to avoid double invocations of the same listener.
    Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
    if (singletonTarget instanceof ApplicationListener) {
      this.defaultRetriever.applicationListeners.remove(singletonTarget);
    }
    this.defaultRetriever.applicationListeners.add(listener);
    // 检索缓存,是一个ConcurrentHashMap
    this.retrieverCache.clear();
  }
}


方法逻辑梳理如下:


如果listener是一个代理,则尝试获取其原始对象。如果获取到的原理对象为ApplicationListener则从defaultRetriever.applicationListeners移除;

否则放入defaultRetriever.applicationListeners。

清理retrieverCache

defaultRetriever是ListenerRetriever类型,内部维护了applicationListeners 集合。


本文这里的defaultRetriever是AbstractApplicationEventMulticaster的成员。defaultRetrieverListenerRetriever类型,内部维护了applicationListeners 集合。本文这里的defaultRetrieverAbstractApplicationEventMulticaster的成员。

private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
private class ListenerRetriever {
  //记录监听器实例
  public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
  // 记录监听器名称
  public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
  private final boolean preFiltered;
  //...
}



getSingletonTarget


getSingletonTarget是获取代理对象后面的单例目标对象()原始对象。如下所示如果是Advised且存在SingletonTargetSource类型的targetSource 则返回targetSource的target对象。否则返回null。

public static Object getSingletonTarget(Object candidate) {
  if (candidate instanceof Advised) {
    TargetSource targetSource = ((Advised) candidate).getTargetSource();
    if (targetSource instanceof SingletonTargetSource) {
      return ((SingletonTargetSource) targetSource).getTarget();
    }
  }
  return null;
}


applicationListeners本文这里有17个监听器(记录的是AbstractApplicationContext的成员):

0 = {ConditionEvaluationReportLoggingListener$ConditionEvaluationReportListener@3203} 
1 = {RSocketPortInfoApplicationContextInitializer$Listener@6339} 
2 = {ServerPortInfoApplicationContextInitializer@6340} 
3 = {RestartApplicationListener@6341} 
4 = {CloudFoundryVcapEnvironmentPostProcessor@6342} 
5 = {ConfigFileApplicationListener@6343} 
6 = {AnsiOutputApplicationListener@6344} 
7 = {LoggingApplicationListener@6345} 
8 = {BackgroundPreinitializer@6346} 
9 = {ClasspathLoggingApplicationListener@6347} 
10 = {DelegatingApplicationListener@6348} 
11 = {ParentContextCloserApplicationListener@6349} 
12 = {DevToolsLogFactory$Listener@6350} 
13 = {ClearCachesApplicationListener@3672} 
14 = {FileEncodingApplicationListener@3695} 
15 = {LiquibaseServiceLocatorApplicationListener@6351} 
16 = {SharedMetadataReaderFactoryContextInitializer$SharedMetadataReaderFactoryBean@6352} 

applicationListenerBeans有如下11个(记录的是容器中的):

0 = "&org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"
1 = "cachingModelPropertiesProvider"
2 = "objectMapperBeanPropertyNamingStrategy"
3 = "optimized"
4 = "delegatingApplicationListener"
5 = "mvcResourceUrlProvider"
6 = "org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker"
7 = "springApplicationAdminRegistrar"
8 = "restartingClassPathChangedEventListener"
9 = "conditionEvaluationDeltaLoggingListener"
10 = "liveReloadServerEventListener"


目录
相关文章
|
2月前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
180 73
|
2月前
|
XML Java 数据格式
Spring Core核心类库的功能与应用实践分析
【12月更文挑战第1天】大家好,今天我们来聊聊Spring Core这个强大的核心类库。Spring Core作为Spring框架的基础,提供了控制反转(IOC)和依赖注入(DI)等核心功能,以及企业级功能,如JNDI和定时任务等。通过本文,我们将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring Core,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
73 14
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
54 1
|
4月前
|
存储 安全 Java
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
49 1
|
4月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
889 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
4月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
321 2
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
48 0
|
5月前
|
消息中间件 设计模式 缓存
spring源码设计模式分析(四)-观察者模式
spring源码设计模式分析(四)-观察者模式
|
5月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
249 5