当前位置: 首页 > news >正文

spring容器

看了片关于spring容器的文章,感觉适合自己理解,记录下。
Spring框架中众所周知的不仅仅是IOC、DI、Spring MVC和AOP。 这些是Spring中最基本的核心功能,更高级的功能包括数据访问模块JDBC、ORM、事务等]。 Spring本身的可扩展性也非常好。 在源代码中也使用了很多设计模式来实现。 了解Spring源代码对Java开发人员来说是非常必要的。 从源代码中也可以学到很多优秀的设计理念。 现在,让我们进行一次从Spring IOC打开Spring源代码的旅行吧。

你可能认为IOC只是在Map的聚会中提到IOC,第一次接触的人是非常高水平、高级的技术,但事实如何呢? 其实,IOC只是映射的集合,不是高级新技术。 请坐qsddx喝茶。

所有的IOC都被称为“控制反转”。 控制翻转的基本概念是,不需要创建对象,但需要说明如何创建对象。

简单来说,我们在代码中创建对象是new关键字,使用Spring后,我们不需要自己去new对象,而是直接从容器中取出,然后自动将其注入到我们需要的对象中。 也就是说,依赖注入。

也就是说,创建对象的控制权不在我们程序员手中,而是全部交给Spring来管理,程序只需要注入即可,所以称为控制反转。

事实上,IOC也被称为IOC容器。 那么,既然是一个容器,就一定要用来放东西,IOC容器是用来保存什么的呢? 如果你了解Spring,你就会发现在Spring中它可以说是面向所有Bean的编程。 Bean是我们交给Spring管理的对象。 今天我们学习的IOC容器是用于存储所有Bean的容器。

IOC的三个核心接口Spring是一个很好的框架,它还支持许多类型的Bean源。 那么,为了统一标准,当然需要定义配置文件接口。 这就是BeanDefinition。 有了BeanDefinitionReader,因为如果有配置标准,则必须定义相关类并转换不同的配置文件; 最终完成Bean分析后,还需要对Bean进行操作,并可以进行BeanFactory。 这三个接口构成了IOC的核心:
BeanDefinition :定义与Bean相关的配置文件的各种信息,包括当前Bean的生成器参数、属性和其他信息。 此接口同样会派生其他支持使用资源和字符串位置参数的实现类,例如BeanDefinitionReader,该类提供了推荐标准,但所有分析都提供了此接口beanfactory :我们访问了bean容器的顶级界面,我们最常用的应用程序上下文界面也实现了beanfactory。 在IOC初始化的三个或更多步骤中,我们大致了解了什么是IOC容器,以及IOC容器用于存储什么。 另外,由于您还熟悉作为IOC核心的三个接口,因此接下来需要知道Bean是如何来的,存储在IOC容器中的是Bean本身还是进一步封装的。

带着这两个问题,让我们详细分析一下IOC的整个初始化过程。

整个IOC初始化过程大致可分为三个步骤:定位、加载和注册。

定位:查找要初始化的Bean。 加载:检测需要初始化以解决封装的Bean。 注册—将在步骤2中加载的Bean放入IOC容器或Map集合中。 我们最常用的Bean通常来自xml配置或注释,但这些配置文件存储在哪里? 在Spring中,配置文件支持以下六个源:

casspathnetworkfilesystemservletcontextannotation接下来,让我们以我们最常用的方法为入口来分析定位过程。 应用程序上下文实现的顶级界面之一是BeanFactory,因此有BeanFactory操作

applicationcontextapplicationcontext=newclasspathxmlapplicationcontext (spring.XML ); application context.get bean (’ my bean ); 应用程序上下文. get bean (my bean.class; 使用传统的Spring时,我们如上所述获得了Bean。 定位入口从ClassPathXmlApplicationContext的入口开始吧。

这里的逻辑非常简单,首先调用setConfigLocation

s 方法设置配置文件,然后核心就在 refresh 方法,refresh 是其父类实现的,而父类中的 refresh 方法的主干就是在 522 行获取一个 beanFactory,后面的所有操作都是围绕 beanFactory 做一些扩展操作。
其实看 522 行的注释也可以知道,最终其还是会调用回子类也就是 AbstractRefreshableApplicationContext 来执行加载 bean 操作:
这里面需要说明的是,核心逻辑是在 623 行,而 624 行实际上是从全局变量内获取 beanFactory:

而这里的全局变量 beanFactory 就是 BeanFactory 的一个默认实现 DefaultListableBeanFactory。了解了这个之后,我们继续回到上面的 refreshBeanFactory:
这个方法其实也很简单,就是创建了一个默认的 DefaultListableBeanFactory,然后就开始调用其子类 AbstractXmlApplicationContext(同时其是 ClassPathXmlApplicationContext 父类)的 loadBeanDefinitions 方法:

加载
执行到上面的方法中,我们可以发现到一个 BeanDefinitionReader 对象 XmlBeanDefinitionReader 被创建了,这就说明到这里差不多要开始加载配置文件了,所以接下来要找主干其实只要跟着这个 BeanDefinitionReader 对象就可以了,我们继续进入 loadBeanDefinitions 方法:

这里面分为了两种情况,一种是根据 Resource 类型,一种是根据 String 类型,我们这里因为传的是一个 String 类型的路径,所以会执行下面的逻辑,但是虽然执行的是下面的逻辑,但是最终还是会将我们传入的 spring.xml 转化成 Resource,从而调用上面的解析方法。

接下来还会经过几次“绕路”,然后还是会进入 XmlBeanDefinitionReader 对象的 loadBeanDefinitions 方法:

在这里我们终于看到了一个令我们惊喜的方法 doLoadBeanDefinitions,因为在 Spring 当中,基本上以 do 开头的方法就是真正的核心处理逻辑方法:

这里面就是调用了两个方法,第一个就是把 resource 转化成 document 对象,然后调用另一个方法准备注册 bean,当然怎么解析我们的 xml 配置文件,我们在这里不做分析,继续看主干注册 bean 的逻辑。

注册
上面调用注册方法之后,最终会由其子类 DefaultBeanDefinitionDocumentReader 来执行:

到这里我们又开到了以 do 开头的方法,说明这里要开始注册了。

这里创建了一个委派者 delegate,进入这个委派者我们可以发现,这里面定义了 xml 文件中的所有节点:

创建好委派者之后,接下来就可以开始调用 parseCustomElement 来进行解析:
到这里又分成了三种情况,是否默认命名空间以及是否默认节点,但是不管是什么情况,最终都是会把节点信息解析出来转换成一个 bean 进行注册,我们进入 parseDefaultElement 解析默认节点方法:
在这里又分为了不同情况去解析 import,alias,bean 节点,也包括了嵌套节点的递归处理方式,我们继续进入 processBeanDefinition 方法:
到这里基本上就要结束注册流程了,调用了 BeanDefinitionReaderUtils 工具类中的一个方法来进行注册:

在这里做了三件事:

获取到 beanName。回到最开始的 DefaultListableBeanFactory,调用 registerBeanDefinition 方法存在别名的话注册一下别名。
在这里最关键的是第二步,我们发现绕了一大圈最终回到了我们前面加载步骤中的 DefaultListableBeanFactory 类(下面这个方法我为了方便截屏,删除了部分的异常判断):

这个方法就是注册 bean 的最后逻辑,首先会判断当前 bean 是否已经被注册,有的话会判断是否允许覆盖之类的一些设置,如果最终都能符合条件,那么就会直接覆盖(795 行),如果当前 bean 是首次创建,那么还需要判断当前整个 ioc 容器是否已经有创建好的 bean,但是最终其实就是 this.beanDefinitionMap.put(beanName, beanDefinition); 这行代码完成了注册,而 beanDefinitionMap 其实就是一个 ConcurrentHashMap 集合。

到这里我们整个 ioc 加载主流程就分析结束了,其实整个逻辑非常简单,而我们之所以会觉得 Spring 复杂难懂,其实是因为 Spring 为了扩展性,可读性,经过了精心设计,整个框架中使用了非常多的设计模式和设计原则,致使我们看源码的时候觉得非常绕,但是只要抓住核心主干,读懂源码也并不是难事。

总结
本文主要讲述了 ioc 的初始化流程,整个过程其实是非常绕非常复杂的,第一次看的话非常容易绕迷路,所以我们需要抓住主流程,理解 ioc 的核心就是三个步骤:定位(找配置文件),加载(解析配置文件),注册(将 bean 添加到 ioc 容器)非常关键,只要抓住这三个步骤,我们就能抓住重点一步步往下跟。所以如果我们把获取 bean 的方式换成注解实现,无非就是把解析 xml 配置文件的过程改为解析注解的过程,核心的后续流程其实还是一样。

**

(仅供学习使用,非商用,如有侵犯,告知删除)

**

相关文章:

  • 数商云供应链系统为机械设备行业打造数据智能应用服务,助力企业智慧决策
  • 纳米/聚合物/化合物/无机材料/多肽/多糖修饰聚苯乙烯微球的研究
  • javaweb JAVA JSP电车租赁系统jsp租赁系统 jsp汽车租赁 电车租赁网站案例源码
  • 中国标志性的图片简笔画,互联网简笔画图片大全
  • 管理经济学知识点汇总
  • 已经安装了torch,但是安装tochvision出现,no module named ‘torch‘
  • 赢未来杂志赢未来杂志社赢未来编辑部2022年第7期目录
  • 阿里云Elasticsearch搜索
  • Sulfo-Cy5 羧酸,Sulfo-Cyanine5 carboxylic acid,花青素荧光染料Cy5标记羧酸
  • AngularJS渲染完成事件捕获
  • spring MVC源码探索之AbstractHandlerMethodMapping
  • Redis线程模型
  • 通过 JFR 与日志深入探索 JVM - 调试 JVM 的工具 WhiteBox API
  • [毕业设计源代码]精品基于SSM的线上点餐系统[包运行成功]
  • C/C++创建tty,创建终端
  • JavaScript 如何正确处理 Unicode 编码问题!
  • Bytom交易说明(账户管理模式)
  • create-react-app项目添加less配置
  • eclipse的离线汉化
  • java2019面试题北京
  • markdown编辑器简评
  • Mithril.js 入门介绍
  • Promise面试题2实现异步串行执行
  • redis学习笔记(三):列表、集合、有序集合
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • TypeScript迭代器
  • Yeoman_Bower_Grunt
  • 代理模式
  • 复杂数据处理
  • 看域名解析域名安全对SEO的影响
  • 驱动程序原理
  • 小程序 setData 学问多
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • Linux权限管理(week1_day5)--技术流ken
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​学习一下,什么是预包装食品?​
  • #pragma预处理命令
  • #Z0458. 树的中心2
  • #考研#计算机文化知识1(局域网及网络互联)
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (2)STL算法之元素计数
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (Java)【深基9.例1】选举学生会
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (三)elasticsearch 源码之启动流程分析
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (转)详解PHP处理密码的几种方式
  • (转)用.Net的File控件上传文件的解决方案
  • .NET 3.0 Framework已经被添加到WindowUpdate
  • .NET CF命令行调试器MDbg入门(一)