spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)

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

上次写到BeanDefinition对象的创建,接着昨天的写

1、解析bean定义的元素

①、标识解析前的初始状态,传到这个方法的时候的参数是Element:Bean的元素,String  beanName:代表bean的id,BeanDefinition:Bean的定义对象也是空的。

②、这个代表结束的标志,这两个标志代表解析式安全的操作

下面的是解析类里的元素,也就是bean的子标签,AbstractBeanDefinition:解析bean本身的元素的。

然后通过bean定义的阅读工具类,来创建bean定义对象

代表通用具体的bean对象定义实现,凡是xml的都是通用

这个类继承了AbstractBeanDefinition

而AbstractBeanDefinition实现了BeanDefinition

这个方法会创建默认的class,就是自定义的类的路径

解析bean定义的属性,全部给解析出来


这个方法就是解析,如果 bean标签中有属性的话,就set进去。

全部AbstractBeanDefinition设置到这个类的里面

这个时候beanDefinition对象创建成功,beanDefiniiton是一个接口,它会有非常多的实现类

这时知道bean标签转换成bean定义对象。

总结:beanDefinition定义解析器就是在解析xml创建的。

AbstractBeanDefinition在这上面的场合是结果,在另外一个场合就会变成原因了。

二、那么如何将bean标签中的properyte标签转换成PropertyValue对象呢?

如果xml标签部设置id和name的话,就生成默认的beanName。就是说不定义id和name的话依然可以使用属性,生成beanName的值就是AbstractBeanDefinition的首字母变为小写


最后转换成BeanDefinitionHolder对象,这里要把别名分开注册,bean名称注册,bean定义注册,都是分开注册的,所以要封装成一个BeanDefinitionHolder对象

返回来之后,下面的方法是否需要装饰bean定义

通过上面的方法一直点下去,可以看到下面的方法,代表用自定义的标签来装饰BeanDefinitionHolder对象

解析完之后就对Bean定义holder对象进行注册,就是说对bean定义对象进行注册。

如何去注册的呢?

先看默认的bean注册定义:

这里就开始注册bean定义对象

这里可以存储256个数量,其实就是一个Map的数据结构而已。

这个方法是判断bean定义对象是否允许覆盖,如果两个bean定义对象相同的话,如果是不允许相同的话,就会抛出异常

没有的话就是一个put操作,把bean的名称也放入到集合当中。

bean名称就存在下面勾起来的

代表是单例的。


然后开始Bean定义Map对象和Bean定义名称然后注册,然后把之前的bean名称给移除掉。

这个代表冻结的这个bean名称

下面的代表是否要重置Bean名称

注册成功之后下面的是注册别名:别名遍历,循环注册。

下面的是别名注册的类:

也是放入到aliasMap里面

这个就是整个BeanDefinition对象放入到map缓存中

二、如何获取到PropertypeValue属性:

1、下面的方法是解析标签:

bean标签里面可以有下面的这么多的子标签

那么如何去解析上面的子标签的呢?

每一种解析都有一个保护的状态

在这里就创建了PropertyValue对象

这个方法是如何解析的?

首先是获取到子标签,子标签就是在<propertype>是否有子标签

判断是否是引用的类型,这个ref就是beanName,获取引用属性,然后创建运行时的bean引用将ref进行封装

如果是value标签的话TypeStringValue:代表封装的值

这些都是将xml转成Java对象

这个就是开始解析子标签

下面的是判断是否有子标签

如果有的话就开始解析子标签,在面向对象的时候,字段定义属性的时候,可以定义数组,集合,基本数据类型,字符串

在下面的方法中是解析子标签的:

比如看如何去解析map的,下面的方法就是如何解析Map的。get

通过下面的对象来对map进行封装:ManageMap

下面的是解决entry子类的问题,都是这样无限嵌套循环下去的,因为在xml中entry标签中也可以定义bean标签。

这个是进行子标签来进行解析的

也是最后封装了RuntimeBeanReference这个对象

通过递归的方式来解析来把所有的标签给解析出来。

回来之后下面的对象Object是层次嵌套封装的对象,然后其让入道把PropertyValue从而放入到Bean定义的集合对象里面。

就是放入到下面的集合里面的

总结:上面的过程就是整个的Bean定义对象到创建,解析,注册,和属性对象的创建。上面的是默认的命名空间是这样的。自定义的命名空间的情况如下:是在spring-context里面的

BeanDefinition接口,PropertyValue,PropertyValues对象称之为set过程。

二、目标:那么获取BeanWapper接口就是get的过程,通过反射获取到bean的实例然后封装到BeanWapper里面。




这里传进来的是bean的name,或者bean的别名和bean的类型。或者参数。

核心的业务和扩展功能都是在这个方法里面:全都是创建bean实例体现的。

这个方法的参数是获取bean的name

transformedBeanName:这个方法是做什么的呢?,是如何转换的呢?

下面的方法传的是bean的name

从BeanName的缓存里面拿

&:代表bean工厂的Bean,就是说它的bean特殊一些,不是普通的对象,它是一个工厂对象

spring容器为什么这么庞大,是因为它把所有的对象全部抽象成bean。

循环引用只是在依赖注入的时候,bean创建的时候是不会产生的。

而在FactoryBean接口是创建对象实例的bean,创建具体的对象。

FactoryBean在beanFactory也是一个bean

这里解决循环引用的,只有单例的时候能够解决循环引用,第一次进来,就不会创建这个实例

第二次进来但是没有初始化的时候如果存在的话,循环引用是先创建对象,先把这个对象先曝光,因为是单例模式。

如果else的话,会判断是否是原型模式,如果是的话就抛异常,因为只有在单例的时候才可以循环引用

面试:Bean工厂是如何解决循环引用的?有一个ObjectFactory

这个方法代表如果 传过来是个别名的话,如果这个别名不等于空的话,就把别名赋给最原始的值:工厂Bean的问题,别名的问题,factoryBean,还有普通的bean

往下走BeanFactory:是父工厂,获取当前的bean,先从父工厂里面去查,如果 父工厂里面有的话,它就返回去,就不会创建bean了。

下面的方法是标记bean创建

下面的是传的是beanname,然后有RootBeanDefinition来操作的,这个又是一个装饰器模式

来进行Bean实例操作。就是将BeanDefinition对象封装成RootBeanDefinition对象

获取到BeanDefinition对象

返回,下面的方法是合并bean定义,因为它有可能有父子关系的,父子关系的,同类型的bean合并成一个bean

这个方法是将父bean和子Bean合并成一个Bean对象

合并之后也放入到bean定义的缓存里面

合并之后就检查合并的bean

如果是抽象类的就抛异常,因为抽象是不允许创建对象实例的。

dependson很少使用了注入,基本都是属性注入

如果配置的是单例的话,开始创建单例对象

如果是多例的就开始创建多例的对象

如果是session,applicationContext,request等等的就从下面创建。然后把属性放入到request

session里面,然后可以在整个生命周期内使用

这个方法是如何获取单例的

下面的方法,所有的类部对象,所有的bean的对象都是由ObjectFactory创建 的,它是内部的接口,来创建真正的bean实例。这个接口也是解决循环引用的接口。这个接口非常的核心。

首先判断单例的bean是否存在,如果不存在的话

在单例bean创建之前

代表这个beanName已经开始循环使用了,只有在单例模式中才会有循环引用。

singletonsCurrentlyInCreation:标识对象实例是否开始创建了。

返回单例实例

然后把单例实例缓存起来了。

单例对象和bean的name一起存进来。这个就是获取实例了

把单例对象放到缓存里面

这个接口缓存 单例对象,但是也被BeanFactory给实现了。

如何去获取这个单例对象呢?委托这个类来从创建bean实例。

开始解析bean,因为存到bean定义对象里面是一个字符串,要转成class类型,所以要进行解析。这个方法是在ObjectFactory对象来调用createBean来创建实例。

解析将字符串解析成beanClass,解析成功 之后,就赋值。

下面的是方法的覆盖,就相当于对方法的增强。

在扩展接口之前是否有代理实例对象,如果存在,就返回这个代理之后的实例

如果没有的话:通过这个doCreateBean来真正的创建实例。

这时BeanWapper对象出现了,这个方法是通过beanName和beanClass(封装到RootBeanDefinition里面了)

如何创建BeanWapper对象的呢?,将字符串mdb转换成class对象然后反射出bean实例。

在Spring5以后通过Supplier来装配对象,通过自定义工厂 的方法来装配对象

通过构造函数来自动装配

开始扩展构造函数了,Autowire就是开始扩展这个构造函数来实现的。

如果说构造函数不存在的话默认有一个初始化实例Bean,这时用到的是策略 模式

如果没有加强的方法就通过反射来实例化

如果有加强的方法就通过CGLIB来实例化:

在把实例化对象包装在BeanWapper里面

这就是BeanWapper的实例化的过程,属性赋值(依赖注入)+循环引用明天写。

相关文章
|
4月前
|
Java 索引 Spring
spring创建bean的过程
spring创建bean的过程
|
3月前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
44 0
|
10小时前
|
XML 存储 Java
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
|
缓存 Java Spring
Spring中Bean创建过程之源码分析
Spring中Bean创建过程之源码分析
74 0
|
4月前
|
XML Java 测试技术
Spring5源码(5)-Spring内部Bean和父子Bean
Spring5源码(5)-Spring内部Bean和父子Bean
33 0
|
XML Java 数据格式
Spring Bean的生命周期和扩展点源码解读
Spring Bean的生命周期和扩展点源码解读
184 0
|
Java Spring
如何解决Spring没有管理的Bean调用Spring管理的Bean
如何解决Spring没有管理的Bean调用Spring管理的Bean
|
Java 容器 Spring
【Spring专题】「实战系列」Spring容器注入Bean对象的方法及梳理
【Spring专题】「实战系列」Spring容器注入Bean对象的方法及梳理
137 0
|
存储 搜索推荐 Java
7天学完Spring:Spring框架搭建和解析以及Bean对象的创建
Spring核心和设计思想 <1>Spring是什么?如何理解Spring<2>IoC和DI是什么?区别? <1>通过容器对象.getBean()获取<2>依赖注入:把一个Bean对象,注入到另一个Bean的属性当中byName:通过Bean的id/名称来匹配如果此时你的id/名称不存在或者说不唯一。怎么绑定?方式一:使用 @Qualifier("XXX")方式二: 使用@Resource(name="XXX")<3>说一下@Autowired 和 @Resource 的区别 这一部分就是关于Spring的部分了,在这里我们主要学习四个部分
|
Java Spring 容器
springboot原理实战(3)-- spring扩展接口BeanPostProcessor,BeanFactoryPostProcessor
springboot原理实战(3)-- spring扩展接口BeanPostProcessor,BeanFactoryPostProcessor
288 0
springboot原理实战(3)-- spring扩展接口BeanPostProcessor,BeanFactoryPostProcessor