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

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

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

相关文章

SQL 术语:Join 中的 Build 和 Probe 是什么意思?

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,…

如何在Vue中实现事件处理?

Vue是一种流行的JavaScript框架,广泛应用于前端开发。在Vue中,事件处理是一个非常关键的概念,可以帮助我们实现用户与页面的交互,今天我们就来探讨一下如何在Vue中实现事件处理。 首先,让我们先了解一下在Vue中如何绑…

[pdf]《软件方法》强化自测题业务建模需求分析共191页,230题

潘加宇《软件方法》强化自测题业务建模需求分析共191页,230题,已上传CSDN资源。 在完成书中自测题基础上,进一步强化。 也可到以下地址下载: 资料http://www.umlchina.com/url/quizad.html 如果需要网盘提取码:uml…

【Python】1. 背景知识

认识 Python 计算机基础概念 什么是计算机? 很多老一辈的人, 管下面这个叫做计算机. 然鹅, 它只是 “计算器”, 和计算机是有很大区别的. 现在我们所说的计算机, 不光能进行算术运算, 还能进行逻辑判断, 数据存储, 网络通信等等功能,。 以至于可以自动的完成非常复杂的工作…

代码随想录day10(2)字符串:反转字符串Ⅱ (leetcode541)

题目要求:给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。如果剩余字符少于 k 个,则将剩余字符全部反转。如果剩余字符小于 2k 但大于或等于 k 个,则反转前…

Zookeeper4:Java客户端、应用场景以及实现、第三方客户端curator工具包

文章目录 Java连接Zookeeper服务端依赖代码使用 应用场景统一命名服务统一配置管理统一集群管理服务器节点动态上下线理解实现模拟服务提供者【客户端代码】-注册服务模拟服务消费者【客户端代码】-获取服务信息进行请求消费 软负载均衡分布式锁理解实现 生产集群安装N台机器合…

Java中的Collection

Collection Collection 集合概述和使用 Collection集合概述 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素 JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现 创建Collection集合的对象 多态的方式 具体的实现类ArrayList C…

MATLAB环境下基于熵的声纳图像分割算法

声纳图像作为准确获取水下信息的重要途径之一,在国防、军事、工程等方面发挥着巨大作用。然而,由于水声信道的复杂多变和声波本身的传播损失,声纳图像往往呈现出分辨率和对比度不高、噪声干扰严重、目标轮廓模糊等特点。 声纳图像的分割指的…

FCIS 2023网络安全创新大会:洞察前沿技术,探索安全新境界(附大会核心PPT下载)

随着信息技术的飞速发展,网络安全问题日益凸显,成为全球关注的焦点。作为网络安全领域的重要盛会,FCIS 2023网络安全创新大会如期而至,汇聚了全球网络安全领域的顶尖专家、学者、企业家和政策制定者,共同探讨网络安全的…

ABAP - SALV教程10 添加可编辑checkbox列

几乎所有的功能报表都会有那么一个选择列,问了业务顾问,业务顾问说是用户不习惯使用报表原生的选择模式。效果图SALV的选择列是通过将列设置成checkbox_hotspot样式,注册单击事件完成勾选功能的。完成步骤 将SEL列设置成checkbox_hotspot样式…

【笔记】OpenHarmony和HarmonyOS区别及应用开发简介

一、概念 OpenHarmony(OH) : OpenAtom OpenHarmonyHarmonyOS(HO):开发 | 华为开发者联盟 (huawei.com) HO当前最高是3.1,在华为mate 60上面也是。关于4.0、5.0和next这类版本说法都是面向用户的,不是开发人员。对于程序员&#…

Springboot 项目读取yaml的配置文件信息给静态方法使用,以及通过配置 ResourceBundle 类读取config.properties

读取yaml 的配置文件 配置文件信息 iot_saas_tenement:user_id: 7........8d9bprivate_key: MII.......qQbj_url: http://4.....5:8088project_name: iot_s.......rojectdevice_name: te.....ice 创建一个类 ProxyProperties 读取配置文件信息,并对外提供get方法 …

内存的检测与排查

内存🐎的检测与排查 文章目录 内存🐎的检测与排查查杀Java Web filter型内存马0x01 内存马简历史0x02 查杀思路0x03 内存马的识别0x04 内存马的查杀 查杀Java Web filter型内存马 0x01 内存马简历史 其实内存马由来已久,早在17年n1nty师傅的…

QT6 libModbus 用于ModbusTcp客户端读写服务端

虽然在以前的文章中多次描述过,那么本文使用开源库libModbus,可得到更好的性能,也可移植到各种平台。 性能:读1次和写1次约各用时2ms。 分别创建了读和写各1个连接指针,用于读100个寄存器和写100个寄存器,读写分离。 客户端&am…

物联网与智慧城市:科技驱动下的城市智能化升级之路

一、引言 随着科技的不断进步和城市化进程的加速,物联网与智慧城市的结合已经成为推动城市智能化升级的关键力量。物联网技术以其强大的连接和数据处理能力,为智慧城市的建设提供了无限可能。本文旨在探讨物联网如何助力智慧城市的构建,以及…

SLAM ORB-SLAM2(21)基础矩阵的计算和评分

SLAM ORB-SLAM2(21)基础矩阵的计算和评分 1. 前言2. 基础矩阵2.1. 对级约束2.2. 推导2.3. 计算原理 3. ComputeF214. CheckFundamental 1. 前言 在 《SLAM ORB-SLAM2(20)查找基础矩阵》 中了解到 查找基础矩阵主要过程&#xff1…

web基础03-JavaScript

目录 一、JavaScript基础 1.变量 2.输出 3.变量提升 4.区块 5.JavaScript数据类型 6.查看数值类型 7.undefined和null 8.布尔值 9.和的区别 10.算数/三元/比较/逻辑/赋值运算符 11.特殊字符 12.字符串 (1)获取字符串长度 (2&am…

备战蓝桥杯Day21 - 堆排序的内置模块+topk问题

一、内置模块 在python中,堆排序已经设置好了内置模块,不想自己写的话可以使用内置模块,真的很方便,但是堆排序算法的底层逻辑最好还是要了解并掌握一下的。 使用heapq模块的heapify()函数将列表转换为堆,然后使用he…

41、网络编程/TCP.UDP通信模型练习20240301

一、编写基于TCP的客户端实现以下功能: 通过键盘按键控制机械臂:w(红色臂角度增大)s(红色臂角度减小)d(蓝色臂角度增大)a(蓝色臂角度减小)按键控制机械臂 1.基于TCP服务器的机械臂…

Python3零基础教程之数学运算专题进阶

大家好,我是千与编程,今天已经进入我们Python3的零基础教程的第十节之数学运算专题进阶。上一次的数学运算中我们介绍了简单的基础四则运算,加减乘除运算。当涉及到数学运算的 Python 3 刷题使用时,进阶课程包含了许多重要的概念和技巧。下面是一个简单的教程,涵盖了一些常…