首先了解下几个类的职能
BeanDefinitionRegistry: 定义Bean的常规操作,来注册BeanDefinition, 内部就是用一个 Map 实现.
SimpleBeanDefinitionRegistry 是 BeanDefinitionRegistry 一个简单的实现。只提供注册表的功能,不提供工厂其他功能。
DefaultListableBeanFactory:ConfigurableListableBeanFactory(其实就是 BeanFactory ) 和 BeanDefinitionRegistry 接口的默认实现:一个基于 BeanDefinition 元数据的完整 bean 工厂。
将Xml读取成Dom实例和将Dom实例注册到BeanDefinition都使用其他类
该类中有一个委托属性,即Dom实例中每个标签的解析委托给了delegate属性。
将beans标签的默认属性的解析委托给delegate属性;解析的默认属性存储在BeanDefinitionParserDelegate
类的beanDefinitionDefaults属性中。
首先回顾下beans标签中可填的属性有哪些
XSD风格的Xml文件以beans标签开头,其属性可以设置一些默认行为,例如
可选值 | 功能说明 |
---|---|
false(default) | spring在启动过程导致在启动时候,会默认加载整个对象实例图,比较耗时,故Spring项目启动都需要较长的时间 |
true | 不会加载整个对象实例图,启动速度较快,但生产环境一般设置为false |
可选值 | 功能说明 |
---|---|
no | 默认不使用autowiring。 必须显示的使用”“标签明确地指定bean。 |
byName | 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。 |
byType | 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置 dependency-check=”objects”让Spring抛出异常。 |
constructor | 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。 |
autodetect | 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。 |
属性是如何填充的?
模板设计模式,在BeanDefinitionDocumentReader
接口中预留了2个方法,在Dom解析成BeanDefinition的前后添加操作处理
首先看一个bean的配置例子,该例子尽量覆盖所有属性和子标签
<bean id="id1" name="beanName1;beanName2;beanName3" class="class1" parent="parent1" abstract="true/false"
lazy-init="true/false/default" scope="singleton/prototype"
autowire="default/byName/byType/constructor/autodetect/no" depends-on="dependentBeanName"
autowire-candidate="default/true/false" primary="true/false"
init-method="init" destroy-method="destroy">
<meta key="metaKey1" value="metaValue1"/>
<meta key="metaKey2" value="metaValue2"/>
<!-- 1、使用constructor-arg属性参数注入
constructor-arg标签属性
index: 参数位置索引(用于指定对应的形参)
name: 参数形参名(用于指定对应的形参)
type: 限定类型
ref: 如果传入引用类型 -->
<!-- index属性,普通类型值-->
<constructor-arg index="0" value="value1">
<description></description>
</constructor-arg>
<!-- index属性,引用类型值-->
<constructor-arg index="1" ref="ref1"/>
<!-- name,type,普通类型值-->
<constructor-arg name="argName1" type="int" value="1"/>
<!-- name,type,引用类型值-->
<constructor-arg name="argName2" type="User" ref="user1"/>
<!-- 2、注入到集合
注入到list或set(简单类型+`String`)-->
<constructor-arg name="...">
<list>
<value>c</value> <value>f</value> <value>r</value>
</list>
</constructor-arg>
<!-- 注入到list或set(对象类型)-->
<constructor-arg name="...">
<list>
<ref bean="person1"/> <ref bean="person0"/> <ref bean="person1"/>
</list>
</constructor-arg>
<!-- 3、注入到map;
如果要注入的元素是对象,则使用属性:`key-ref="..." value-ref="..." value-type="..."`来定义`<entry>`-->
<constructor-arg name="...">
<map>
<entry key="1" value="value of 1"/> <entry key="2" value="value of 2"/> <entry key="3" value="value of 2"/>
</map>
</constructor-arg>
<!-- 4、注入到数组(Array)
同样地,复杂对象使用`<ref bean=""/>`-->
<constructor-arg name="">
<array>
<value>1</value> <value>2</value> <value>3</value>
</array>
</constructor-arg>
<property name="name1" value="value2"/>
<property name="name2" ref="ref2" />
</bean>
,
或者;
分割;若id为空,则name值中第一个作为beanName,其余的作为该bean的别名还需要检测该bean的beanName和别名在该容器中是否唯一
AttributeAccessorSupport
Map
):其Map中一个Entry对应一个meta标签,Entry的key为name,value为BeanMetadataAttribute实例MethodOverride:
LookupOverride
MethodOverrides:
用法介绍
//类
public class TestChangeMethod {
public void changeMe(){
System.out.println("changeMe");
}
}
public class TestMethodReplacer implements MethodReplacer{
@Override
public Object reimplement(Object obj, Method method, Object[] args)throws Throwable {
System.out.println("我替换了原有的方法");
return null;
}
}
//xml配置
<bean id="testChangeMethod" class="test.replacemethod.TestChangeMethod">
<replaced-method name="changeMe" replacer="replacer"/>
</bean>
<bean id="replacer" class="test.replacemethod.TestMethodReplacer"/>
// 最终使用容器获取该类调用changeMe方法的输出结果是:
// 我替换了原有的方法
ReplaceOverride
对于构造函数的存储;分为2种类型:1.不带index属性的标签;2.带index属性的标签
ConstructorArgumentValues
因为值的类型多种多样,故Spring设置了ValueHolder用于存储解析出来的值。
ConstructorArgumentValues.ValueHolder
下面重点了解下constructor-arg标签的值被解析后是如何存放的
首先先总览一下解析值所涉及的类
接下来逐一详细分析,若无法理解可先跳过,先查看后面的方法解析
bean子标签(这三个属性就不讲解了,就是bean标签的存储形式)
BeanDefinitionHolder
ref子标签(该标签parent属性和bean属性二者必须有一个)
RuntimeBeanReference
idref子标签:从来没见过,也少用,不分析
value子标签
TypedStringValue
null子标签
TypedStringValue
ManagedList
ArrayList
注意:
index
属性,则子标签中只能有一个赋值
标签(如ref, value, list等);该解析过程和constructor-arg类似,不再赘述
我们最终解析的结果都存放在该对象中,在此先对该对象做分析
GenericBeanDefinition用于承载解析出来的Bean信息
一个bean配置的所有信息,都会存在该AbstractBeanDefinition类中
在了解Xml中的配置是怎样被封装到BeanDefinition中时,首先看个Xml配置的例子,该例子尽量涵盖所有情况
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="default/true/false" default-merge="default/true/false"
default-autowire="default/byName/byType/constructor/no" default-autowire-candidates="bean1,bean2"
default-init-method="defaultInit" default-destroy-method="defaultDestroy">
<bean id="beanA" class="com.example.demo.循环依赖.BeanA">
<property name="beanB