下面从元素解析及信息提取开始,也就是:
1,
2,
3,
我们进一步看步骤AbstractBeanDefinition beanDefinition=parseBeanDefinitionElement(ele,beanName,containingBean)中,对其他属性的解析过程,(我想再次重申一次,查看Spring源码是一个艰苦且枯燥的过程,如果能坚持下来,你会发现收获巨大。)
1,创建用于承载属性的BeanDefinition
BeanDefinition是一个接口,在Spring中存在三种实现:RootBeanDefinition,ChildBeanDefinition,以及GenericBeanDefinition.三种实现均继承了AbstractBeanDefinition,其中BeanDefinition是配置文件<bean>元素标签在容器中的内如表现形式。<bean>元素标签拥有class,scope,lazy-init等配置属性,BeanDefinition则提供了相应的beanClass,scope,lazeInit属性,BeanDefinition和<bean>属性是一一对应的。其中RootBeanDefinition是最常用的实现类,它对应一般的<bean>元素标签,GenericBeanDefinition是自2.5版本以后新加入的bean文件配置属性定义类,是一站式服务类。
在配置文件中可以定义父<bean>和字<bean>,父<bean>用RootBeanDefinition表示,而子<bean>用ChildBeanDefinition表示,而没有父<bean>的<bean>就使用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象。
Spring通过BeanDefinition将配置文件中的<bean>配置信息转换为容器的内部表示,并将浙西BeanDefinition注册到BeanDefinitionRegistry中。Spring容器的BeanDefinitionRegistry就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从BeanDefinitionResistry中读取配置信息。它们之间的关系如下图所示:
因此,要解析属性首先要创建用于承载属性的实例,也就是创建GenericBeanDefinition类型的实例。而代码createBeanDefinition(className,parent)的作用就是实现此功能。
1).下面说下子元素constructor-arg的解析
对构造函数的解析式非常常用,也是非常复杂的,下面举个构造函数的小例子
<beans>
<!-- 默认情况是按照参数的顺序注入,当指定index索引后就可以改变注入参数的顺序 -->
<bean id= "helloBean" class="com.HelloBean">
<constructor-arg index="0">
<value>刘哲</value>
</cibstructor-arg>
<constructor-arg index="1">
<value>你好</value>
</bean>
</beans>
对于constructor-arg子元素的解析,Spring是通过parseConstructorArgElements函数来实现的,具体的代码如下:
这个结构中遍历所有子元素,也就是提取所有constructor-arg,然后进行解析,具体的解析被放置在了另个函数parseConstructorArgElement中,
可以看到对于是否定义index属性,Spring的处理是不同的,关键在于属性信息被保存的位置。
了解整个流程后,继续尝试了解解析构造函数配置中子元素的过程,进入parsePropertyValue:
最后设计到了对子元素的处理,例如下面:
<constructor-arg>
<map>
<entry key="key" value='value'/>
</map>
</constructor-arg>
在这里处理map是怎么实现的呢,parsePropertySubElement中实现了对各种子元素的分类处理。
上面的函数中已经理清了所有可支持子类的分类处理。
在下一节中我们将具体分析都是那么属性配置到了GenericBeanDefiniton中,会比较轻松些,这些源码阅读起来会比较累,但还是希望愿意看的人坚持下来,因为看完这些你会发现自己进入了另一片天地,是java提高必不可少 的。