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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 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集合中。

相关文章
|
10天前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
10天前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
3月前
|
XML Java 数据格式
深度解析 Spring 源码:从 BeanDefinition 源码探索 Bean 的本质
深度解析 Spring 源码:从 BeanDefinition 源码探索 Bean 的本质
77 3
|
10小时前
|
XML 缓存 Java
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
|
4月前
|
XML Java 开发者
【Spring源码解读 底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理讲解
【Spring源码解读 底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理讲解
|
4月前
|
XML 缓存 Java
天天用 Spring,bean 实例化原理你懂吗
天天用 Spring,bean 实例化原理你懂吗
44 0
|
缓存 Java Spring
Spring中Bean创建过程之源码分析
Spring中Bean创建过程之源码分析
74 0
|
XML Java 数据格式
Spring Bean的生命周期和扩展点源码解读
Spring Bean的生命周期和扩展点源码解读
184 0
|
XML 缓存 Java
Spring IOC源码:实例化前的准备工作
Spring IOC源码:实例化前的准备工作
52 0
Spring IOC源码:实例化前的准备工作
|
缓存 Java 开发者
Spring Bean的创建过程及相关扩展点(下)
Spring Bean的创建过程及相关扩展点
108 0