在方法 parseDefaultElement()
中,若是遇到标签 为 bean 则调用 processBeanDefinition()
方法进行 bean 标签解析java
整个过程分为四个步骤spring
- 调用 BeanDefinitionParserDelegate.parseBeanDefinitionElement() 进行元素解析,解析过程当中若是失败,返回 null,错误由 ProblemReporter 处理。若是解析成功则返回 BeanDefinitionHolder 实例 bdHolder。BeanDefinitionHolder 为持有 name 和 alias 的 BeanDefinition。
- 若实例 bdHolder 不为空,则调用 BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired() 进行自定义标签处理
- 解析完成后,则调用 BeanDefinitionReaderUtils.registerBeanDefinition() 对 bdHolder 进行注册
- 发出响应事件,通知相关的监听器,完成 Bean 标签解析
parseBeanDefinitionElement()架构
没有对 Bean 标签进行解析,只是在解析动做以前作了一些功能架构,主要的工做有:ide
- 解析 id、name 属性,肯定 alias 集合,检测 beanName 是否惟一
- 调用方法 parseBeanDefinitionElement() 对属性进行解析并封装成 GenericBeanDefinition 实例 beanDefinition
- 根据所获取的信息(beanName、aliases、beanDefinition)构造 BeanDefinitionHolder 实例对象并返回
这里有必要说下 beanName 的命名规则:函数
- 若是 id 不为空,则 beanName = id;
- 若是 id 为空,可是 alias 不空,则 beanName 为 alias 的第一个元素,若是二者都为空,则根据默认规则来设置 beanName
BeanDefinition
- 解析 bean 标签的过程其实就是构造一个 BeanDefinition 对象的过程
<bean>
元素标签拥有的配置属性,BeanDefinition 均提供了相应的属性,与之一一对应
- 因此咱们有必要对 BeanDefinition 有一个总体的认识
BeanDefinition 是一个接口,它描述了一个 Bean 实例ui
- 包括属性值、构造方法值和继承自它的类的更多信息
- 它继承 AttributeAccessor 和 BeanMetadataElement 接口
- AttributeAccessor :定义了与其它对象的(元数据)进行链接和访问的约定,即对属性的修改,包括获取、设置、删除
- BeanMetadataElement:Bean 元对象持有的配置元素能够经过
getSource()
方法来获取
BeanDefinition 整个结构以下图:this

- 父 <bean> 用 RootBeanDefinition表示
- 子 <bean> 用 ChildBeanDefinition 表示
- 而没有父 <bean> 的就使用RootBeanDefinition 表示。GenericBeanDefinition 为一站式服务类
- AbstractBeanDefinition对三个子类共同的类信息进行抽象。
解析 Bean 标签
- 在
BeanDefinitionParserDelegate.parseBeanDefinitionElement()
中完成 Bean 的解析
- 返回的是一个已经完成对
<bean>
标签解析的 BeanDefinition 实例
- 在该方法内部,首先调用
createBeanDefinition()
方法建立一个用于承载属性的 GenericBeanDefinition 实例
- 委托 BeanDefinitionReaderUtils 建立
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
- 建立完 GenericBeanDefinition 实例后,再调用
parseBeanDefinitionAttributes()
- 该方法将建立好的 GenericBeanDefinition 实例当作参数,对 Bean 标签的全部属性进行解析
完成 Bean 标签基本属性解析后spa
- 会依次调用 parseMetaElements()、parseLookupOverrideSubElements()、parseReplacedMethodSubElements() 对子元素 meta、lookup-method、replace-method 完成解析
三个子元素的做用以下:设计
- meta:元数据。
- lookup-method:Spring 动态改变 bean 里方法的实现。方法执行返回的对象,使用 Spring 内原有的这类对象替换,经过改变方法返回值来动态改变方法。内部实现为使用 cglib 方法,从新生成子类,重写配置的方法和返回对象,达到动态改变的效果。
- replace-method:Spring 动态改变 bean 里方法的实现。须要改变的方法,使用 Spring 内原有其余类(须要继承接口org.springframework.beans.factory.support.MethodReplacer)的逻辑,替换这个方法。经过改变方法执行逻辑来动态改变方法。
meta 子元素
- meta :元数据。当须要使用里面的信息时能够经过key获取
- meta 所声明的 key 并不会在 Bean 中体现,只是一个额外的声明,当咱们须要使用里面的信息时,经过 BeanDefinition 的
getAttribute()
- 解析过程较为简单,获取相应的 key - value 构建 BeanMetadataAttribute 对象,而后经过
addMetadataAttribute()
加入到 AbstractBeanDefinition
委托 AttributeAccessorSupport 实现code
- AttributeAccessorSupport 是接口 AttributeAccessor 的实现者
- AttributeAccessor 接口定义了与其余对象的元数据进行链接和访问的约定,能够经过该接口对属性进行获取、设置、删除操做
lookup-method 子元素
- lookup-method :获取器注入,是把一个方法声明为返回某种类型的 bean 但实际要返回的 bean 是在配置文件里面配置的
- 该方法能够用于设计一些可插拔的功能上,解除程序依赖
举个栗子:


replace-method 子元素
- replaced-method :能够在运行时调用新的方法替换现有的方法,还能动态的更新原有方法的逻辑
- 该标签使用方法和 lookup-method 标签差很少,只不过替代方法的类须要实现 MethodReplacer 接口
举个栗子:



constructor-arg 子元素

- 首先获取 index、type、name 三个属性值,而后根据是否存在 index 来区分
- 其实二者逻辑都差很少,总共分为以下几个步骤(以有 index 为例)
- 构造 ConstructorArgumentEntry 对象并将其加入到 ParseState 队列中。ConstructorArgumentEntry 表示构造函数的参数
- 调用 parsePropertyValue() 解析 constructor-arg 子元素,返回结果值
- 根据解析的结果值构造 ConstructorArgumentValues.ValueHolder 实例对象
- 将 type、name 封装到 ConstructorArgumentValues.ValueHolder 中,而后将 ValueHolder 实例对象添加到 indexedArgumentValues 中
parsePropertyValue()
对子元素进一步解析
- 提取 constructor-arg 子元素的 ref 和 value 的属性值,对其进行判断,如下两种状况是不容许存在的
- ref 和 value 属性同时存在
- 存在 ref 或者 value 且又有子元素
- 若存在 ref 属性,则获取其值并将其封装进 RuntimeBeanReference 实例对象中
- 若存在 value 属性,则获取其值并将其封装进 TypedStringValue 实例对象中
- 若是子元素不为空,则调用 parsePropertySubElement() 进行子元素进一步处理
须要调用 parsePropertySubElement()
进一步处理
property 子元素

Spring 调用 parsePropertyElements()