[读书笔记]AbstractApplicationContext中refresh方法详解

简介: [读书笔记]AbstractApplicationContext中refresh方法详解

关联博文:

AbstractApplicationContext中refresh方法详解

Spring中refresh分析之prepareRefresh方法详解

Spring中refresh分析之obtainFreshBeanFactory方法详解

Spring中refresh分析之prepareBeanFactory方法详解

Spring中refresh分析之postProcessBeanFactory方法详解

Spring中refresh分析之invokeBeanFactoryPostProcessors方法详解

Spring中refresh分析之registerBeanPostProcessors方法详解

Spring中refresh分析之initMessageSource方法详解

Spring中refresh分析之initApplicationEventMulticaster方法详解

Spring中refresh分析之onRefresh方法详解

Spring中refresh分析之registerListeners方法详解

Spring中refresh分析之finishBeanFactoryInitialization方法详解

Spring中refresh分析之finishRefresh方法详解


Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,refresh()是一个模板方法,refresh()方法的作用是在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。


refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入


refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()中ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();”这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动。


本文开始,我们将分析refresh的系列方法。

【1】方法概览

AbstractApplicationContext 的refresh方法如下所示:

@Override
public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    prepareRefresh();
    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);
    try {
      // Allows post-processing of the bean factory in context subclasses.
      postProcessBeanFactory(beanFactory);
      // Invoke factory processors registered as beans in the context.
      invokeBeanFactoryPostProcessors(beanFactory);
      // Register bean processors that intercept bean creation.
      registerBeanPostProcessors(beanFactory);
      // Initialize message source for this context.
      initMessageSource();
      // Initialize event multicaster for this context.
      initApplicationEventMulticaster();
      // Initialize other special beans in specific context subclasses.
      onRefresh();
      // Check for listener beans and register them.
      registerListeners();
      // Instantiate all remaining (non-lazy-init) singletons.
      finishBeanFactoryInitialization(beanFactory);
      // Last step: publish corresponding event.
      finishRefresh();
    }
    catch (BeansException ex) {
      if (logger.isWarnEnabled()) {
        logger.warn("Exception encountered during context initialization - " +
            "cancelling refresh attempt: " + ex);
      }
      // Destroy already created singletons to avoid dangling resources.
      //为了防止Bean资源占用,在异常处理中销毁已经在前面过程中生成的单件Bean
      destroyBeans();
      // Reset 'active' flag.
      //重置 active 标识
      cancelRefresh(ex);
      // Propagate exception to caller.
      throw ex;
    }
    finally {
      // Reset common introspection caches in Spring's core, since we
      // might not ever need metadata for singleton beans anymore...
      resetCommonCaches();
    }
  }
}

方法解释如下:


① 准备刷新的上下文环境;

② 获取到应用上下文维护的beanFactory,默认是DefaultListableBeanFactory。并设置刷新标志refreshed为true

③ 对beanFactory做了一些基础设置的配置,比如BeanClassLoader、BeanExpressionResolver、ApplicationContextAwareProcessor、ApplicationListenerDetector监听器检测器以及默认的环境信息bean。并设置了哪些不需要自动注入以及哪些已经解析过可以直接使用。

④ BeanFactory的后置处理;

⑤ 注册并调用BeanFactoryPostProcessor,扫描获取BeanDefinition;

⑥ 注册BeanPostProcessor到BeanFactory;

⑦ 初始化MessageSource消息源;

⑧ 初始化事件广播器;

⑨ 初始化themeSource并创建WebServer;

⑩ 检查监听bean并将这些bean向容器中注册

(11) 初始化所有non-lazy-init bean,比如我们的controller、service、mapper等;

(12) 发布容器事件,结束Refresh过程

(13) 重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据。。。

【2】异常捕捉中的两个方法

① destroyBeans


这是一个模板方法,销毁所有上下文管理的bean。默认实现是销毁上下文缓存的所有单例bean,通过触发DisposableBean.destroy()方法或者指定的具体destroy-method。可以重写以在标准单例销毁之前或之后添加特定于上下文的bean销毁步骤,如果上下文的BeanFactory仍处于活动状态。

protected void destroyBeans() {
  getBeanFactory().destroySingletons();
}

DefaultListableBeanFactory的销毁实例方法如下所示,其首先触发父类DefaultSingletonBeanRegistry的销毁方法,然后清空Set<String> manualSingletonNames

@Override
public void destroySingletons() {
  super.destroySingletons();
  updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
  clearByTypeCache();
}

DefaultSingletonBeanRegistry的destroySingletons方法。

public void destroySingletons() {
  if (logger.isTraceEnabled()) {
    logger.trace("Destroying singletons in " + this);
  }
  synchronized (this.singletonObjects) {
  //设置状态
    this.singletonsCurrentlyInDestruction = true;
  }
  String[] disposableBeanNames;
  synchronized (this.disposableBeans) {
    disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
  }
  // 循环遍历销毁每一个disposableBean
  for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
    destroySingleton(disposableBeanNames[i]);
  }
  //清空集合
  this.containedBeanMap.clear();
  this.dependentBeanMap.clear();
  this.dependenciesForBeanMap.clear();
  // 清空缓存 包括一级、二级、三级以及registeredSingletons
  clearSingletonCache();
}

② cancelRefresh

这个方法简单,就只重置标志:

  • 将beanFactory的SerializationId置为null
  • active设置为false

【3】resetCommon

重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据。

// AbstractApplicationContext
protected void resetCommonCaches() {
  ReflectionUtils.clearCache();
  AnnotationUtils.clearCache();
  ResolvableType.clearCache();
  CachedIntrospectionResults.clearClassLoader(getClassLoader());
}

ReflectionUtils.clearCache如下所示:

public static void clearCache() {
  declaredMethodsCache.clear();
  declaredFieldsCache.clear();
}

AnnotationUtils.clearCache如下所示:

public static void clearCache() {
  AnnotationTypeMappings.clearCache();
  AnnotationsScanner.clearCache();
}


ResolvableType.clearCache如下所示:

public static void clearCache() {
  cache.clear();
  SerializableTypeWrapper.cache.clear();
}
private static final ConcurrentReferenceHashMap<ResolvableType, ResolvableType> cache =
new ConcurrentReferenceHashMap<>(256);
目录
相关文章
|
9月前
|
SQL 前端开发 关系型数据库
TienChin 开篇-运行 RuoYiVue
下载完毕之后,这个项目当中存在一个 ruoyi-ui 这个是前端,只是放在了这个项目当中方便我们进行
59 0
|
9月前
|
存储 XML Java
【spring源码系列-06】refresh中obtainFreshBeanFactory方法的执行流程
【spring源码系列-06】refresh中obtainFreshBeanFactory方法的执行流程
67 0
|
10月前
|
缓存 Java Spring
Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(二)(下)
Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(二)(下)
62 0
|
10月前
|
XML 存储 Java
Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(一)(上)
Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(一)
68 0
|
10月前
|
存储 XML 缓存
Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(一)(下)
Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(一)
55 0
|
10月前
|
存储 XML 前端开发
Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(二)(上)
Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(二)
44 0
|
10月前
|
Kubernetes 监控 Perl
【k8s 系列】k8s 学习二十七 - 6,k8s 自身原理之 Service
好不容易,终于来到 k8s 自身的原理之 关于 Service 的一部分了 前面我们用 2 个简图展示了 pod 之间和 pod 与 node 之间是如何通信息的,且通信的数据包是不会经过 NAT 网络地址转换的
|
XML API Android开发
Preference组件探究之源码解读
Preference组件探究之源码解读
|
XML Java 程序员
spring源码之refresh第二篇
上篇文章对spring核心启动方法refresh做了整体的解读,但是只是泛泛而谈,接下来会出一系统文章对每个方法的源码进行深刻解读。
|
测试技术
软件测试面试题:QTP中的Action有什么作用?有几种?
软件测试面试题:QTP中的Action有什么作用?有几种?
103 0