spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)

一、这是全局图:

如何通过set和get来看源码:

1、Spring工厂通过原材料进入我们的spring工厂,然后通过工厂获取到我们所需要的目标。

2、我们的目标全部依赖于原材料。

3、原材料到spring工厂里面称之为set方法

4、获取原材料中的某个目标,称之为get方法

总结:有舍才有得,获得某个目标,必须要失去某个东西。

分析:在spring中如何将原材料转化成目标的?在这个期间分成很多个小目标

然后组合起来,形成总目标,看这个目标是从哪个母体里产生出来的。就是说要得到某个目标,必须要有它的母体,没有母体,目标是无法达到的。而母体就是主要依据。我们理解的工厂主要是get东西。spring也是这样做的,只不过是对这个工厂做了很大的一个扩展。

那么它的扩展依据又是啥呢?依赖原材料各种各样的属性,各种各样的场合针对每一个点给出相应的方案,综合起来就是一套完整的架构,这就是spring的核心思想,思想很简单,但是里面有很多的核心组件。

二、我要产生一个对象,我要产生一个实例,这是一个问题,解决这个问题在java中是用接口

接口就是目标与母体的一个桥梁,我们就可以称之为接口。接口中的每一个方法就是实现的某一个步骤。

1、spring中的原材料就是所定义的类,原材料可以放到xml中,就称之为xml的原材料,放入到注解里面,就称之为注解的原材料,核心不变,就是类,类的结构是什么样子的呢?类有多态:

ListableBeanFactory:这个就是解决多态实例的问题的,代表一个对象有多种实例。

HierarchicalBeanFactory:解决继承的问题的。这两个接口是解决获取对象的接口,是get方法有get必然有set的,ConfigurableBeanFactory:提供一些组件的内部的配置,所以它用set,set某个资源进去,动态设置一些属性。

AutowireCapableBeanFactory:它具有创建对象和依赖注入的问题。

ConfigurableListableBeanFactory:把所有的功能进行汇总。

这些接口没有和具体的环境联系起来,与环境联系起来是从bean定义开始的,解决对象关系创建的问题的。

2、在上面的图中,beanFactory:获取某个实例而已,解决总目标的一个抽象接口,一看到接口的时候就知道解决了什么问题了。问题是由具体的场合来解决,一种是xml,一种是注解来解决,还有可能spring外部帮解决,还有一种可能是springBoot的环境,有4种解决手段。

首先看下beanFactory的继承体系:它是总目标的入口,获取基本bean实例的接口,传个类型,别名,一个名称进去,beanFactory就是工厂的模式,我们就可以通过这个工厂给返回结果。

上面的是总目标的接口,是整个外部的一个核心,总目标必然要依赖子目标来实现。

1、由于spring是一个框架,所以是针对所有的类,解决多场景的问题才称之为框架。

2、由于是很多种类,很多个场景,规范下命名,在spring里面就称之为bean定义对象。

用上面的BeanWapper的接口来代替所有定义的类。

3、如何获取到BeanWpper对象呢?

如何通过实例,获取到类,只有得到类,才能够new对象

入口:①、xml  ②、注解

用入口来装原材料

xml:将所有的class对象全部封装到xml文件里面,只要配置了原材料,就可以从工厂里面获取到BeanWapper的接口,进而返回具体的实例。

将class对象和bean定义对象进行分开,但是把它俩放到统一的入口

1、比如说上面的类是原材料,只有定义这个类,才能够new 对象。在类里面有基本数据类型和复杂的数据类型。

2、用一个对象代替所有的类,所以抽象出BeanDefinition对象

3、用一个对象代替所有的属性,所以抽象出了上面的图中的PropertyValue对象,用PropertyValues来代替所有的对象。下面的这样写就是给原材料所有的属性赋值。如果是基本的数据类型的话用value来标识,如果是复杂的数据类型的话用ref来标识。

<property>就是一个属性的完整的标签。

4、如何把上面的属性中的字符串转换成Java中认识的对象呢?它就抽象成一个BeanDefinitionValueResolver:Bean定义值得解析器,将属性里面的字面量转换成需要的类型。

5、如何将xml中属性的字符串的字面量转成java对象中的基本数据类型呢?所以又抽象出上面图中的TypeConverter接口。

在上面的图中的称之为set操作,

6、在xml中如何去组装上面set的对象,最后怎么get出来的?怎么获取到xml文件呢?bean对象,属性的对象是放到了xml文件里面了,所以需要对xml文件进行解析,将其转成bean定义对象,进而转成PropertyValue和PropertyValues对象。前期称之为属性的封装的过程。取数据的过程就称之为set方法。

7、首先我们要获得BeanDefinition这个对象,这是get,BeanDefinition这个对象是在xml文件里面,可以把xml文件看成是母体。可以把BeanDefinition看成是个目标。

先读取xml,再解析,解析之后封装成上面的BeanDefinition和PropertyValue和PropertyValues对象,然后再保存这些对象。

总结:这是矛盾思想,每一个事务的产生必须由某个事务延申出来。这就是由 一个母体产生主体的原因。学源码应该学习思想,而不是框架的流程。

BeanFactory:是总目标接口,只要getBean就可以了。BeanDefinition和PropertyValue和PropertyValues和。。。是内部的接口,子目标是BeanDefinition。

主要看的是spring-beans的组件

spring-core主要提供的是spring-beans的基础的功能而已

core里面主要提供两个入口:1、提供基本的bean定义,就是bean策略。

instantiator:提供 bean实例化的功能。lang:是java语言的功能

core:里面有几个是核心的:一个是编码和解码,一个是annotation,将类上的所有的注解做了一个封装,convet:针对类型转换的封装,env:是环境的封装,就是profile,用springBoot的时候用的最多,有测试环境,开发环境。

io:比如现在的xml文件放到了本地,它也有可能放到远程,io就是将资源进行全部的抽象。

里面重要的是Resource和ResourceLoader很重要。

log:对日志的封装。serializer:对序列化的封装。

style:是对打印样式的封装。

task:是对同步和异步线程的封装,里面继承了executor线程池的接口。

spring将java中的对象全部做了一个封装,这也就是spring为什么这么庞大,全部抽象出它自定义的类,这才是面向对象的特点。将属性进行一个包装,代替所有的场合,这是面向对象的思维。

关心对象哪个时机调用,哪个时机被创建?

在xml中:bean解析对象的接口里面会生成BeanDefinition对象

Bean定义阅读时个接口的原因,有可能它是一个xml,也有可能是个注解。只是提供规范,具体的场景是由实现类来提供

Bean的注册:既能注册Bean的定义,也能注册Bean的别名,因为继承了AliasRegistry接口

接口就是解决问题的一套规范,那我们该怎么解决问题呢?

这时首先需要定目标,找到主体,下面勾起来的就是主体。从主体里面获取到需要的条件。

这就是产生一个结果,从母体里面获取到需要的结果依赖外面的一些实现类。

这时就又有了BeanDefinitionReader的接口:读取beandefinition接口定义的地方。

读取了xml文档,还要去解析xml文档。

BeanDefinitionParser:Bean的解析接口,是用委托的方式,不是自身解析的,是用委托的

方式,获取Bean定义对象。从母体里面就获取到了

如何去获取到PropertyValue对象呢,依据还是在Bean定义标签里面的property属性


现在看下源代码:如何获取到BeanDefinition对象,总目标是BeanFactor,因为先从xml看,所以是XMLBeanFactor,里面的Resource就是对资源的一种封装。

一、如何获取到Bean定义对象:

1、首先是加载Bean定义对象,只是从文档里面来加载。

  1. publicXmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException{
  2.        super(parentBeanFactory);
  3. this.reader.loadBeanDefinitions(resource);
  4. }

  5. }

这个类是总入口,总目标是给外部来调用的,而内部调用的属于子目标。

2、然后从上面的方法进去:通过对这个Resource进行编码和解码

3、然后从loadBeanDefinitions这个方法进去:这个方法主要是对资源进行一些解析。在这个方法里面主要获取的是InputStream。因为文档转成inputstream才能够被读取。

4、然后从这个方法进去:

5、这个时候是开始加载bean定义了,把输入流转成Document对象。

在转成Document对象之前,有两种xml文件,一种 是xsl,另一种是xsd.

在下面的方法中就可以进行模式的校验

在下面的方法中就可以进行模式的校验

获取Document文档之后,然后解析:

BeanDefinitionDocumentReader documentReader =

createBeanDefinitionDocumentReader():类部的类在解析


下面的方法是调用core包里面的


bean的实例化也是这么操作的:

这个就是用反射对类进行实例化的过程


在上面的图中,有创建阅读的接口:

因为在spring-context.xml文件里面有默认的命名空间:


解析自定义标签:通过这个XmlReaderContext解析自定义的标签

自定义的标签就是namespaceHandler,这个接口很核心,但是在springBoot里面就不核心了。

注册的bean定义对象,勾起来的是bean定义文档的阅读对象

在这个bean标签里面可以定义很多个属性,而上面的对象就是对这些的属性的封装,也包括属性


这个方法是解析document:在spring里面凡是带有do方法的,都是执行最终的结果的


方法的参数Element  root是xml文件里面的beans标签,这里用到了内部的委托的设计模式,委托bean定义的解析,它的解析就是委托的模式

这里会创建一个委托类:

这里会创建一个Bean定义的解析的委托,把自定义标签的解析器传到里面。

回来之后:这里会判断是否是默认的命名空间,然后从命名空间里面去取值

默认的命名空间,默认的命名空间只有bean标签。

这个就是真正的开始解析,把委托和root(根:beans)传进来

下面的方法是普通的一个xml文件的一种解析。一种是默认的命名标签的解析,一种是自定义的命名标签的解析。

NodeList:获取所有的子元素,就是所有的bean,或者和xml文件中和bean标签同级的标签。

delegate.isDefaultNamespace:通过委托类来判断元素是否是命名空间。

parseDefaultElement:这个就是解析一些普通定义的标签

如果是parseCustomElement(ele):解析自定义的标签。

先看默认的解析:这个方法里面。这个就是自定义的四个根。

所以在xml文件中可以定义<import>标签,<alias>标签,<beans>标签,这三种标签一定是和<bean>标签同级的。

别名可以在内部定义,也可以在外部定义

勾起来的name就是内部可以定义多个别名,但是id只能允许有一个,id表示bean的name。

name如果没有逗号的话,就和id的值相同 ,如果有逗号的话,就有多个别名。

从下面的方法进去:

这个类就是所有bean定义的属性

bean定义就是将这些所有的属性进行get和set封装

从解析bean标签进去:

下面的方法是核心:而且用了BeanDefinitionHolder的装饰器模式将Bean定义对象封装成bean持有者对象,通过委托类来解析bean定义的元素。通过BeanDefinitionHolder这个对象来实现bean定义注册的

BeanDefinitionHolder这个类里面封装了id,别名,和bean的定义对象

通过这三个元素实现Bean的注册。

这个元素已经是bean了

下面的方法是对Bean标签和属性进行一个完整的解析,BeanDefinition这个值首先是null,因为没有创建bean。

获取id和name,然后定义一个别名的集合。

以点进行分割,然后获得到nameArr得数组,然后存储到别名的集合

下面的方法是检查bean是否是独立性:

由于bean定义的id,要映射,要存在map里面,所以必须要在map里面保证它的唯一性。

下面的是检验的方法,检验是否是已经使用过的名称,如果是已经使用的就添加到以使用的集合中去。

这个对象AbStractBeanDefinition就是创建BeanDefinition的


这个类实现了BeanDefinition接口:

上面的过程就是BeDefinition的创建的过程:

总结:

1、总结如何从xml文件获取到beandefinition对象

1.1 beandefinitionReader对象读取xml文件 ,获取document对象

 1.2 从document通过beandefinitionPaserDeletar委托解析器解析默认标签和自定义标签成beandefinitionHolder(封装beandefinition,beanName,aliseNames)对象

     1.3 根据beandefinitionHolder对象通过beandefinitionRegister接口进行beandefinition注册到Map集合同时注册别名到Map集合中。

相关文章
|
5天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
21天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
11天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
37 9
|
11天前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
27 5
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
110 5
|
1月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
163 2
|
10天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
23 2
 SpringBoot入门(7)- 配置热部署devtools工具