上次写到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的实例化的过程,属性赋值(依赖注入)+循环引用明天写。