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

简介: 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集合中。

相关文章
|
8月前
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
913 4
|
9月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
374 0
|
9月前
|
负载均衡 Java Nacos
Spring Cloud五大组件
Spring Cloud五大组件
|
4月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
8月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
546 70
|
5月前
|
JSON 前端开发 Java
Spring MVC 核心组件与请求处理机制详解
本文解析了 Spring MVC 的核心组件及请求流程,核心组件包括 DispatcherServlet(中央调度)、HandlerMapping(URL 匹配处理器)、HandlerAdapter(执行处理器)、Handler(业务方法)、ViewResolver(视图解析),其中仅 Handler 需开发者实现。 详细描述了请求执行的 7 步流程:请求到达 DispatcherServlet 后,经映射器、适配器找到并执行处理器,再通过视图解析器渲染视图(前后端分离下视图解析可省略)。 介绍了拦截器的使用(实现 HandlerInterceptor 接口 + 配置类)及与过滤器的区别
492 0
|
5月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1018 0
|
6月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
763 0
|
2月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
361 3