一、这是全局图:
如何通过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定义对象,只是从文档里面来加载。
publicXmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException{
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
这个类是总入口,总目标是给外部来调用的,而内部调用的属于子目标。
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集合中。