spring源码
IOC容器
IOC:(inversion of control):控制反转,将组件间的依赖关系从程序内部提到外部来管理。
DI(dependency injection):依赖注入;将组件中的依赖通过外部以参数或其他方式注入。
(导演、剧本、角色、演员)
导演负责协调剧本、角色、演员的关系,将角色的办演者的控制权反转。
注入方式:
构造方式注入
属性注入:(需要用时进行注入)
接口注入:实现接口,与属性没有差别,还会增加接口,不建议。
功能分析
1 | public class BeanFactoryTest { |
上面代码主要进行一下几点:
- 读取配置文件
- 根据配置文件中的配置找到对应得类的配置,并实例化。
- 调用实例化后的实例
数据准备阶段逻辑:
首先对传入的resource参数做封装,目的考虑到Resource可能存在编码要求的情况,
其次通过SAX读取Xml文件的方式,来准备InputSource对象,
最后将准备的数据传入真正的核心处理部分XmlBeanDefinitionReader
1 | /** |
获取XML的验证模式
验证方式常见为两种:DTD和XSD
DTD:(Document Type Definition)即文档类型定义,是一种XML约束模式语言,是XML文件的验证机制,属于XML文件组成的一部分。DTD是一种保证XML文档格式正确的有效方法。 DTD文档包含:元素的定义规则,元素间关系的定义规则,元素可使用的属性,可使用的实体或符号规则,下面看下声明方式的代码:
1 | <!-- |
XML Schema 语言就是XSD(XMLSchemas Definition)。描述了XMl文档的结构,可以指定一个指定的XML Schema来验证某个XML文档,检查XML文档是否符合要求。
要声明名称空间,
1 | xmlns="http://www.springframework.org/schema/beans" |
还需指定XML Schemas文档的存储位置
1 | xsi:schemaLocation="http://www.springframework.org/schema/beans |
验证模式的读取
从上文代码可以看到验证模式的读取:
1 | int validationMode = getValidationModeForResource(resource); |
1 | /** |
如何设定指定的验证模式:通过调用XmlBeanDefinitionReader中的setValidationMode方法进行设定
自动检测验证模式的功能是在函数detectValidationMode函数中将自动检测验证模式的工作委托给专门处理类XmlValidationModeDetector,调用了XmlValidationModeDetector中的detectValidationMode(InputStream inputStream)方法。
1 | /** |
XmlValidationModeDetector.java
1 | /** |
spring用来检测验证模式的办法就是判断是否包含DOCTYPE,包含就是DTD,否则就是XSD.
取Document
XmlBeanFactoryReader类将读取文档委托给DocumentLoader去执行,真正调用的为DefaultDocumentLoader
1 | /** |
解析以及注册BeanDefinitions
XmlBeanDefinitionReader.java
1 | /** |
其中参数doc是通过上一节loadDocument加载转换过来的。这个方法很好的应用了面向对象的单一职责的原则,将逻辑处理委托给单一的类处理,处理类就是BeanDefinitionDocumentReader(接口)。
1 | /** |
默认标签的解析
spring的标签包括默认标签和自定义标签,两种标签的用法以及解析方式有很大的不同
DefaultBeanDefinitionDocumentReader.java
1 | //使用Spring的Bean规则解析Document元素节点 |
1 |
|
此时我们先分析对bean标签的读取
- 首先先委托BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder,经过这个方法后,bdHolder实例已经包含我们配置文件中配置的各种属性了。
- 返回的bdHolder不为空的话,若存在默认标签的子节点下再有自定义属性的话,还需要再次对自定义标签进行解析
- 解析完成后,对bdHolder进行注册,注册委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法。
- 最后发出响应事件,通知想关的监听器,这个bean已经加在完成了。
时序图如下:
解析BeanDefinition
1 | BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(); |
我们从此处这里进入解析的方法了。
BeanDefinitionParserDelegate.java
1 | //解析<Bean>元素的入口 |
解析步骤:
- 提取元素中的id以及name属性
- 进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例中。
- 如果检测到bean没有指定beanName,那么使用默认规则为此Bean生成beanName。
- 将获取到的信息封装在BeanDefinitionHolder中。
解析其他属性
1 | //详细对<Bean>元素中配置的Bean定义其他属性进行解析,由于上面的方法中已经对 |
创建用于属性承载的BeanDefinition
解析属性要先创建用于承载属性的实例,也就是创建GenericBeanDefinition类型的实例。下面的代码就是实现此功能。
1 | protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) |