ApplicationContext容器

news2024/9/23 17:25:40

ApplicationContext容器

1.概述

      ApplicationContext接口代表了一个Spring容器,它主要负责实例化、配置和组装bean。ApplicationContext接口间接继承了BeanFactory接口,相较于BeanFactory一些基本的容器功能,ApplicationContext接口是在BeanFactory接口基础上进行了扩展,增加了国际化、事件广播、获取资源等一些新的功能。

2.ApplicationContext系列类图

      从以上类图中可以看出,ApplicationContext接口的派生体系,是一个非常庞大的家族。

  • FileSystemXmlApplicationContext:默认从文件系统中加载bean定义信息的ApplicationContext实现。
  • ClassPathXmlApplicationContext:默认从ClassPath中加载bean定义信息的ApplicationContext实现。
  • XmlWebApplicationContext:专门用于Web应用程序的ApplicationContext实现。SpringMVC 中默认使用的容器。
  • AnnotationConfigApplicationContext:是一个基于注解配置类的ApplicationContext实现。SpringBoot 中默认使用的容器。
  • AnnotationConfigServletWebServerApplicationContext:是SpringBoot一个基于注解配置类的servlet web应用程序的ApplicationContext实现。容器中会一个内置的servlet 服务器。
  • AnnotationConfigReactiveWebServerApplicationContext:是SpringBoot一个基于基于注解配置类的reactive web应用程序的ApplicationContext实现。容器中会一个内置的reactive 服务器。

3.refresh()方法

3.1概述

      refresh方法是Spring容器中一个非常核心的方法。经过refresh方法后,一个完整的Ioc容器已经创建完成。refresh方法是在ConfigurableApplicationContext接口定义的,而给出具体这个方法实现的是在AbstractApplicationContext的类中。

      从refresh方法的源码可以发现,refresh方法中调用了12个子方法。这12个子方法其实就是Spring创建Ioc容器的12个步骤。

      refresh方法其实是使用了模版方法模式。模板方法模式定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以在不改变一个算法结构的情况下,重定义该算法的某些特定步骤。

      refresh方法中调用的12个步骤方法,为Ioc容器的创建定义了一个总体框架。在各种具体的ApplicationContext的子类中,会根据自身具体的特性,再对这12个步骤方法进行重写,但是创建容器的总体步骤是不变的。

3.2源码

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      //准备刷新上下文环境:设置其启动日期和活动标志,初始化上下文环境中的占位符属性源
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      //实例化DefaultListableBeanFactory实例并返回,对BeanFactory进行定制,加载BeanDefinition的信息
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      //配置beanFactory容器的特性
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         //在容器初始化后,预留在子类中的上下文中,可以对容器进行修改
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         // 执行注册在容器中的各种BeanFactory的处理器
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         //注册Bean的各种处理器。处理器会在创建bean时调用。
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         //初始化上下文的Message源。如:i18n国际化处理
         initMessageSource();

         // Initialize event multicaster for this context.
         //为上下文初始化应用程序广播器
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         //在特定的上下文中,留给子类来的初始化其他的特殊bean
         onRefresh();

         // Check for listener beans and register them.
         // 查看ApplicationListener类型的bean,并注册他们。
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         // 对上下文环境中剩余的单例bean完成初始化(非惰性的bean)
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
               // 调用LifecycleProcessor生命周期处理器的onRefresh方法并发布ContextRefreshedEvent通知,
         // 来完成上下文的刷新过程。
         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,已避免占用资源。
         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();
      }
   }
}
 3.2.1prepareRefresh

      prepareRefresh方法主要是对上下文的刷新做了一些准备工作,该方法中主要做了以下几件事情。

  1. 激活开关

      prepareRefresh方法的激活开关,主要是程序中记录了当前的时间戳,打开了当前上下文是否处于活动状态的标志(设置为true) ,关闭当前上下文是否处于关闭状态的标志(设置为false)。

  1. 初始化占位符

   initPropertySources方法是用于初始化上下文环境中的占位符属性。但是在AbstractApplicationContext类中,initPropertySources方法只是一个空方法,没有任何实现代码。该方法是专门预留给子类扩展实现用的。

   我们可以自己实现一个继承至AbstractApplicationContext的子类,并在子类的initPropertySources方法中,根据自己的需求来设置需要验证的占位符。

  1. 对占位符属性进行验证

      Spring对占位符属性进行验证时,先获取ConfigurableEnvironment类型的实例,然后再调用这个实例的validateRequiredProperties方法来进行验证。

      在validateRequiredProperties方法中,会判断占位符的属性值是否为空,若值为空,就会抛出异常。默认情况下,一般是对系统中的环境变量和JVM的环境变量来进行判断。

3.2.2obtainFreshBeanFactory

      obtainFreshBeanFactory方法从方法名上,顾名思义就是获取BeanFactory容器。Spring经过这个函数之后,ApplicationContext就已经拥有了BeanFactory 的全部功能。obtainFreshBeanFactory方法很简单,它主要调用了两个方法,这两个方法分别是refreshBeanFactory和getBeanFactory方法。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

   //创建BeanFactory容器实例

   refreshBeanFactory();

   //返回创建的BeanFactory容器实例

   return getBeanFactory();

}

refreshBeanFactory方法

      refreshBeanFactory方法的作用主要是创建BeanFactory容器的实例。refreshBeanFactory方法在AbstractApplicationContext类中只是一个虚方法,没有给出具体的实现。这个方法的具体实现是在子类AbstractRefreshableApplicationContext类中给出的。具体源码如下所示:

protected final void refreshBeanFactory() throws BeansException {

   //判断是否已经创建了BeanFactory容器

   //如果已经创建,则销毁容器中的bean,并关闭容器

   if (hasBeanFactory()) {

      destroyBeans();

      closeBeanFactory();

   }

   try {

       //使用new方式创建一个DefaultListableBeanFactory的容器

      DefaultListableBeanFactory beanFactory = createBeanFactory();

      //给容器设置一个序列化的id

      beanFactory.setSerializationId(getId());

      //自定义DefaultListableBeanFactory容器的相关属性

      customizeBeanFactory(beanFactory);

      //给容器加载BeanDefinition

      loadBeanDefinitions(beanFactory);

      this.beanFactory = beanFactory;

   }

   catch (IOException ex) {

      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);

   }

}

      通过以上源码可以发现refreshBeanFactory方法主要做了以下几件事情:

  1. 创建DefaultListableBeanFactory容器

      对于DefaultListableBeanFactory容器的创建, Spring中直接是new的方式创建了一个DefaultListableBeanFactory的实例,非常简单。DefaultListableBeanFactory是Bean工厂的一个默认实现,它提供了容器的基本功能。

  1. 给容器指定一个序列化的id
  2. 自定义容器的相关属性
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {

   if (this.allowBeanDefinitionOverriding != null) {

      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);

   }

   if (this.allowCircularReferences != null) {

      beanFactory.setAllowCircularReferences(this.allowCircularReferences);

   }

}

      customizeBeanFactory方法用于自定义容器的相关属性。方法中判断了allowBeanDefinitionOverriding和allowCircularReferences这两个属性的值是否为空,不为空的话,就对容器进行属性值设置。

      allowBeanDefinitionOverriding属性表示是否允许覆盖同名的BeanDefinition,默认值是true。

      allowCircularReferences属性表示是否允许bean之间能否进行循环依赖,默认值也是true。

  1. 给容器加载BeanDefinition

      BeanDefinition定义了描述Bean的元数据信息。BeanDefinition的加载,其实就是把Spring外部对Bean的定义信息转化成IoC容器中内部数据结构的过程。

      IoC容器对Bean的管理和依赖注入功能的实现,其实都是通过对其持有的BeanDefinition进行各种相关操作来完成的。

      Spring外部对BeanDefinition的定义是多种形式的,BeanDefinition的定义有xml文件,properties文件和注解等形式。对于这三种形式的BeanDefinition,Spring分别提供了XmlBeanDefinitionReader,PropertiesBeanDefinitionReader,AnnotatedBeanDefinitionReader三个类来加载相应的BeanDefinition信息。

getBeanFactory方法

      getBeanFactory方法的作用主要是返回已经创建的BeanFactory容器实例,比较简单,无需展开。

3.2.3prepareBeanFactory

      prepareBeanFactory方法主要是对beanFactory容器的特性进行一些配置的准备工作。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

   // Tell the internal bean factory to use the context's class loader etc.

   //设置容器的ClassLoader

   beanFactory.setBeanClassLoader(getClassLoader());

   //设置容器的SpEL语言解析器,增加对SpEL语言的支持。

   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

   //添加容器的属性编辑器

   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));



   // Configure the bean factory with context callbacks.

   //为容器注册ApplicationContextAwareProcessor的后置处理器

   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

   //设置容器忽略自动装配的接口

   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);

   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);

   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);

   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);

   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);



   // BeanFactory interface not registered as resolvable type in a plain factory.

   // MessageSource registered (and found for autowiring) as a bean.

   //对容器注册自动装配所依赖特殊类型

   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);

   beanFactory.registerResolvableDependency(ResourceLoader.class, this);

   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);

   beanFactory.registerRe

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1483824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Snagit 2024:让你的屏幕活动瞬间变得生动有力 mac/win版

Snagit 2024 屏幕录制与截图软件是一款功能强大的工具,专为现代用户设计,以满足他们在工作、学习和娱乐中对屏幕内容捕捉和分享的需求。这款软件结合了屏幕录制和截图功能,为用户提供了一种高效、便捷的方式来捕捉屏幕上的精彩瞬间。 Snagit…

HelixToolKit的模型旋转操作

前面加载了模型以后,鼠标拖动和缩放比较好操作;但是旋转似乎没有, 操作了一阵,也不是没有,应该是还不熟悉; 旋转的指示器在右下角,现在U面看到正面, 想看一下模型的背面&#xff0…

压缩视频大小的软件有哪些?5款软件推荐

压缩视频大小的软件有哪些?随着高清摄像设备的普及和网络速度的不断提升,视频文件变得越来越庞大,动辄数百兆甚至数GB的大小常常让用户在分享和存储时感到头疼。幸运的是,市面上有许多优秀的视频压缩软件可以帮助我们轻松应对这一…

鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?

“2024年是原生鸿蒙的关键一年,我们要加快推进各类鸿蒙原生应用的开发,集中打赢技术底座和三方生态两大最艰巨的战斗。”这是余承东在新年信中表达的决心。 随后在1月18日举行的鸿蒙生态千帆启航仪式上,华为宣布 HarmonyOS NEXT 鸿蒙星河版系…

《2023跨境电商投诉大数据报告》发布|亚马逊 天猫国际 考拉海购 敦煌网 阿里巴巴

2023年,跨境电商API接口天猫国际、京东国际和抖音全球购以其强大的品牌影响力和市场占有率,稳坐行业前三的位置。同时,各大跨境电商平台消费纠纷问题层出不穷。依据国内知名网络消费纠纷调解平台“电诉宝”(315.100EC.CN&#xff…

前端按钮动画

效果示例 代码示例 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevic…

pygame绘制繁花曲线

------------★Pygame系列教程★------------ Pygame教程01&#xff1a;初识pygame游戏模块 Pygame教程02&#xff1a;图片的加载缩放旋转显示操作 Pygame教程03&#xff1a;文本显示字体加载transform方法 Pygame教程04&#xff1a;使用pygame.draw绘制矩形、多边形、圆、椭圆…

【DDD】学习笔记-聚合和聚合根:怎样设计聚合?

今天我们来学习聚合&#xff08;Aggregate&#xff09;和聚合根&#xff08;AggregateRoot&#xff09;。 我们先回顾下上一讲&#xff0c;在事件风暴中&#xff0c;我们会根据一些业务操作和行为找出实体&#xff08;Entity&#xff09;或值对象&#xff08;ValueObject&…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:禁用控制)

组件是否可交互&#xff0c;可交互状态下响应点击事件、触摸事件、拖拽事件、按键事件、焦点事件和鼠标事件。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 enabled enabled(value: boolean) 设置组…

SqlServer配置定时备份

在企业系统环境中&#xff0c;为了确保SQL Server数据库受到意外的人为错误、系统故障、病毒攻击等因素的影响&#xff0c;我们通常会选择定期备份数据库。但是随着时间尺度的拉长&#xff0c;如果每次备份都要去手动执行一次的话&#xff0c;可能会觉得有些麻烦&#xff0c;或…

网页版图像处理软件开发服务:助您项目在市场竞争中脱颖而出

在当今数字化时代&#xff0c;图像处理在各个行业中扮演着重要的角色&#xff0c;虎克专注于提供定制化的网页版图像处理软件开发服务&#xff0c;为您的项目保驾护航。 1.网页版图像处理软件的定制化需求 1.1行业特定功能 针对不同的业务需求&#xff0c;深入了解行业特点&…

MapFi:面向室内定位的Wi-Fi基础设施自主地图构建

文献来源&#xff1a; X. Tong, H. Wang, X. Liu and W. Qu, "MapFi: Autonomous Mapping of Wi-Fi Infrastructure for Indoor Localization," in IEEE Transactions on Mobile Computing, vol. 22, no. 3, pp. 1566-1580, 1 March 2023, doi: 10.1109/TMC.2021.31…

FastAPI 的 quickstart

从这一章往后我们就正式开始学习 FastAPI 了 代码 FastAPI 环境安装 python 环境安装 根据要求至少需要 python 3.8及其以上&#xff0c;可以去 python 官网 自行下载安装, 本文中我们用 python 3.11 FastAPI 环境安装 pip install fastapi pip install "uvicorn[sta…

【Java程序设计】【C00322】基于Springboot的高校竞赛管理系统(有论文)

基于Springboot的高校竞赛管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的高校竞赛管理系统&#xff0c;本系统有管理员、老师、专家以及用户四种角色&#xff1b; 管理员&#xff1a;首页、个人中心、管…

Stable Cascade又升级了,现在只需要两个模型

Stable Cascade这个模型&#xff0c;大家如果还有印象的话&#xff0c;是需要下载三个模型的&#xff0c;分别是Stage_a,Stage_b和Stage_c,如果全都下载下来&#xff0c;需要20多个G&#xff0c;但是最近使用ComfyUI做尝试的时候&#xff0c;发现官方的案例中已经没有用到单独的…

Redis是单线程还是多线程?

单线程为什么这么快的原因&#xff1a; 后来引入了多线程是因为&#xff1a;

微信小程序云开发教程——墨刀原型工具入门(动态组件)

引言 作为一个小白&#xff0c;小北要怎么在短时间内快速学会微信小程序原型设计&#xff1f; “时间紧&#xff0c;任务重”&#xff0c;这意味着学习时必须把握微信小程序原型设计中的重点、难点&#xff0c;而非面面俱到。 要在短时间内理解、掌握一个工具的使用&#xf…

[Linux]如何理解kernel、shell、bash

文章目录 概念总览kernelshell&bash 概念总览 内核(kernel) &#xff0c;外壳(shell) &#xff0c;bash kernel kernel是指操作系统中的核心部分&#xff0c;用户一般是不能直接使用kernel的。它主要负责管理硬件资源和提供系统服务&#xff0c;如内存管理、进程管理、文件…

Python列表中添加删除元素不走弯路

1.append() 向列表中添加单个元素&#xff0c;一般用于尾部追加 list1 ["香妃", "乾隆", "贾南风", "赵飞燕", "汉武帝"]list1.append("周瑜") print(list1) # [香妃, 乾隆, 贾南风, 赵飞燕, 汉武帝, 周瑜]…

bootstrap-table 多层组合表头

如下图所示的二层组合表头 来人&#xff0c;上代码&#xff01; table.bootstrapTable({url: $.fn.bootstrapTable.defaults.extend.index_url,pk: id,sortName: id,search: false,showToggle: false,showColumns: false,showExport: false, commonSearch: false,columns: [[…