ApplicationContext容器

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

alfred自定义脚本执行报错,alfred task launch path not accessible问题解决

alfred自定义脚本执行报错,alfred task launch path not accessible 原因是mac升级后 /usr/lib/php 已经不存在了,可以改由zsh方式执行,如下图 右击打开目录 将执行脚本放入目录 code如下: <?phprequire ./Util.php; $qs $argv; $query $qs[1]; date_default_timezon…

CMDB对企业和IT管理员有什么用?

CMDB这个词在ITSM相关文档和IT管理领域经常遇到&#xff0c;但鲜有人能解释什么是CMDB&#xff0c;CMDB是怎么帮助到企业的&#xff1f;如果这些问题也困扰着您&#xff0c;那让我们来聊一聊CMDB&#xff0c;为什么需要CMDB&#xff0c;以及如何设置自己的CMDB。 1. 资源管理&a…

[ai笔记14] 周鸿祎的ai公开课笔记1

欢迎来到文思源想的ai空间&#xff0c;这是技术老兵重学ai以及成长思考的第14篇分享&#xff01; 本周二月的最后一周&#xff0c;并不是闲下来了&#xff0c;反而是开始进行一些更多的深入实践&#xff0c;关于gpt的主体架构、关于prompt&#xff0c;同时也看了不少书和直播&…

【Linux】基本指令(下)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Xshell (操作系统:CentOS 7.9 64位) 日志 日志的概念: 网络设备、系统及服务程序等&#xff0c;在运作时都会产生一个叫log的事件记录&#xff1b;每一行日志都记载着日期、时间、使用者及动作等相关…

【大厂AI课学习笔记NO.60】(13)模型泛化性的评价

我们学习了过拟合和欠拟合&#xff0c;具体见我的文章&#xff1a;https://giszz.blog.csdn.net/article/details/136440338 那么今天&#xff0c;我们来学习模型泛化性的评价。 泛化性的问题&#xff0c;我们也讨论过了&#xff0c;那么如何评价模型的泛化性呢&#xff1f; …

中科数安|防止电脑文件资料外泄

#防止电脑文件资料泄漏# 中科数安提供了一系列解决方案来防止电脑文件资料外泄。 www.weaem.com 这些解决方案包括以下几个方面&#xff1a; 访问控制&#xff1a;实施严格的文件访问控制&#xff0c;确保只有授权的人员能够访问和编辑核心文件。使用身份验证和权限管理系统&a…

1255942-05-2,DBCO-C6-Amine,可以用于构建分子结构和生物活性分子

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;1255942-05-2&#xff0c;DBCO C6 NH2&#xff0c;DBCO-C6-Amine&#xff0c;二苯并环辛炔-C6-氨基 一、基本信息 【产品简介】&#xff1a;DBCO-C6-NH2 is a multifunctional molecule with excellent chemical re…

【C++精简版回顾】13.(重载1)运算符重载+,前置后置++

1.友元函数方式为类重载运算符 &#xff08;友元函数声明可以放在类任何地方&#xff09; 1.类 class MM { public:MM() {}MM(int grade,string name):grade(grade),name(name){}friend MM operator(MM object1, MM object2);void print() {cout << this->grade <…

基于springboot音乐翻唱与分享平台源码和论文

1.1研究背景 随着网络不断的普及发展&#xff0c;音乐网站与分享平台依靠网络技术的支持得到了快速的发展&#xff0c;首先要从用户的实际需求出发&#xff0c;通过了解用户的需求开发出具有针对性的首页、音乐资讯、音乐翻唱、在线听歌、留言反馈、个人中心、后台管理、客服功…

Spring 事务常见错误(下)

通过上一章的学习&#xff0c;我们了解了 Spring 事务的原理&#xff0c;并解决了几个常见的问题。这一章我们将继续讨论事务中的另外两个问题&#xff0c;一个是关于事务的传播机制&#xff0c;另一个是关于多数据源的切换问题通过这两个问题&#xff0c;你可以更加深入地了解…

CopyUtil对象复制工具类

介绍 CopyUtil是一个通用的对象复制工具类&#xff0c;其中包含单体复制和列表复制两个方法。 单体复制方法copy通过传入源对象和目标class&#xff0c;利用Java反射机制创建目标对象&#xff0c;并将源对象的属性值复制到目标对象中。若源对象为空&#xff0c;则返回null。若…

如何使用支付宝沙箱环境本地配置模拟支付并实现公网远程访问【内网穿透】

文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级子域名8. 测试使用固定二级子域名访问 前言 在沙箱环境调试支付SDK的时候&#xff0c;往往沙箱环境部署在本地&#xff0c;局限性大&#xff0c;在沙箱环境…

WordPress上传图片错误:不是合法的JSON响应

最近在进行WordPress迁移至新服务器的过程中&#xff0c;遭遇到一个棘手的问题&#xff0c;即在编辑文章并上传图片时&#xff0c;不断遭遇“此响应不是合法的JSON响应”的错误。经过多次验证和搜索&#xff0c;最终确定问题的根本原因并不在于禁用 Gutenberg 编辑器或安装经典…

maven配置文件(一)Settings配置

一、仓库 1、关系 我们依赖的外部服务是需要有地方进行存储的&#xff0c;而存储的地方就称之为仓库。其中仓库又分为本地仓库、中央仓库、镜像仓库、私服。 &#xff08;1&#xff09;本地仓库 当项目在本地编译或运行时&#xff0c;直接加载本地的依赖服务无疑是最快的。默…

微信如何设置自动回复消息,提升沟通效率的?

在日常微信聊天过程中&#xff0c;我们可能会频繁遇到相同问题的客户提问&#xff0c;特别是对于从事销售工作的朋友们而言&#xff0c;客户添加好友后的第一句话常常为“在吗”或“你好”。当我们拥有大量好友&#xff0c;手动逐一回复可能会耗费大量时间。因此&#xff0c;自…

甘特图资源视图和任务视图的区别

甘特图(Gantt chart)是一种常用的项目管理工具,用于直观地展示项目的进度和各项任务的时间安排。甘特图包含资源视图和任务视图两种视角。 一个项目的甘特图demo &#xff1a; https://zz-plan.com/share/87f1340286f1343ba5 资源视图主要显示项目中不同资源的分配和利用情况…

预处理大致解析(参见《C语言深度解剖》更好得到学习)

预处理大致解析&#xff08;参见《C语言深度解剖》更好得到学习&#xff09; 一、预定义符号二、#define三、其他预处理指令<font face "楷体" size 5 color blue>//库文件包含 //#include < filename.h > //直接在库文件所在的标志路径查找&#xff…

谷歌seo推广效果怎么判断?

要想判断谷歌SEO推广效果&#xff0c;核心在于观察和分析几个关键指标&#xff0c;一个网站最重要的自然就是流量&#xff0c;没有流量的网站说到底就是一个被雪藏的花架子&#xff0c;没什么意义&#xff0c;所以看流量自然就是最重要的指标&#xff0c;SEO做得好&#xff0c;…

阿里云服务器2核4G租用价格_2核4G支持人数新能测评

阿里云2核4G服务器多少钱一年&#xff1f;2核4G配置1个月多少钱&#xff1f;2核4G服务器30元3个月、轻量应用服务器2核4G4M带宽165元一年、企业用户2核4G5M带宽199元一年。可以在阿里云CLUB中心查看 aliyun.club 当前最新2核4G服务器精准报价、优惠券和活动信息。 阿里云官方2…

远程IT技术支持软件有哪些

什么是远程支持软件 远程支持软件允许 IT 部门和管理员通过内部网络或互联网从远程位置连接和控制设备&#xff0c;以解决技术问题并自动执行日常任务。企业使用远程支持软件来解决技术问题并增强安全性&#xff0c;而无需技术人员物理访问需要支持的设备。 远程支持解决方案…