Spring源码之旅(3)_BeanDefinition的解析与注册
一、 BeanDefinition
spring可以通过xml配置文件定义bean,beanFactory可以创建、查找配置文件中定义的这些bean,spring内部是如何将配置文件中所定义的bean变成可以让beanFactory创建与管理的呢?这是依靠BeanDefinition进行实现。BeanDefinition是一个接口,它描述了一个bean的实例,保存了bean的定义信息,是bean在内存中的描述形式。xml配置文件所定义的每个bean在内存中都有对应的Bedifinition对象进行描述。BeanFactory在查找,创建及管理bean时,会先查找其在内存中所保存的BeanDefinition,然后再根据BeanDefinition中的bean描述内容创建bean或返回所需的bean信息。
根据面向接口编程的原则,spring定义了接口BeanDefinitionRegistry注册管理所有的Bedifinition,实现此接口就可以管理bean的定义,DefaultListableBeanFactory类实现了此接口,因此DefaultListableBeanFactory类及其子类具有管理beanDefinition的功能。
Spring读取分析配置文件,根据配置文件中的定义,为这些bean创建对应的BeanDifinition,并将BeanDifinition注册至beanFactory中(具体表现为注册在DefaultListableBeanFactory类型的beanFactory)。当用户需要使用bean时,将传入bean的名称或类型给beanFactory,beanFactory从其所保存的beanDefinition中查找,当找到符合条件的beanDefinition后,则将根据beanDefinition中的bean信息创建bean对象,并返回给用户。
二、 BeanDefinition解析注册序列图
三、 实现源码分析
3.1 beanDefinition加载入口
AbstractRefreshableApplicationContext类在刷新beanFacotry时方法refreshBeanFactory()内部有调用loadBeanDefinitions(beanFactory)方法加载beanDefinition,不过在此类中loadBeanDefinitions还只是抽象方法,其真正在子类AbstractXmlApplicationContext中进行实现。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { // 创建XmlBeanDefinitionReader对象,用于读取配置文件中的BeanDefinition XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 模板方法,空实现 initBeanDefinitionReader(beanDefinitionReader); // 利用beanDefinitionReader加载BeanDefinition信息 loadBeanDefinitions(beanDefinitionReader); } |
3.2 XmlBeanDefinitionReader
XmlBeanDefinitionReader类用于从资源中加载BeanDefinition, AbstractBeanDefinitionReader对BeanDefinitionReader接口进行了默认实现,除了
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
方法。
XmlBeanDefinitionReader继承对AbstractXmlBeanDefinitionReader类未实现的方法进行了实现,并在其内部调用了doLoadBeanDefinitions(InputSource inputSource, Resource resource)加载BeanDefinition:
//获取resource的验证模式<br/> int validationMode = getValidationModeForResource(resource); //创建documentLoader创建xml的Document对象 Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, this.namespaceAware); return registerBeanDefinitions(doc, resource); |
在此方法内部利用documentLoader(默认为DefaultDocumentLoader类)获取xml配置文件的Document对象,然后调用registerBeanDefinitions(doc, resource)方法。
registerBeanDefinitions(doc, resource)方法:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { …………….. // Read document based on new BeanDefinitionDocumentReader SPI. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //获取解析之前beanFactory中所拥有的beanDefinition数量 int countBefore = getBeanFactory().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //返回从此document中所加载的beanDefintion数量 return getBeanFactory().getBeanDefinitionCount() - countBefore; } |
BeanDefinitionDocumentReader 默认使用的DefaultBeanDefinitionDocumentReader类,注册和解析beanDefinition进入DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法。
3.3 DefaultBeanDefinitionDocumentReader
DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); //模板方法,空实现 preProcessXml(root); //从根节点root解析beanDefinitions parseBeanDefinitions(root, delegate); //模板方法,空实现 postProcessXml(root); } |
首先查看createHelper方法:
protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) { //创建并最终返回BeanDefinitionParserDelegate对象 BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); //初始化根节点<beans>的属性值,并作为<beans>节点下各bean相关属性的默认配置值 delegate.initDefaults(root); return delegate; } |
DefaultBeanDefinitionDocumentReader类有一个defaults属性,它是DocumentDefaultsDefinition类型,其内部保存了<beans>元素的一些属性值,将作为<beans>下面的<bean>子节点值的默认配置。
parseBeanDefinitions(root, delegate)方法在其内部调用了
parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
方法:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //解析import if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //解析alias else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //解析bean else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } } |
在此方法中,对<beans>节点下面的<import>,<alias>,<bean>子节点进行了解析
在importBeanDefinitionResource(ele)方法对import所导入的xml文件,进行递归地解析
processAliasRegistration(ele)则对别名进行了注册
processBeanDefinition方法对bean进行了解析,实现为:
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { //注册beanDefinition // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); }………….. |
调用了BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法将<bean>节点解析成了BeanDefinitionHolder对象,然后再将BeanDefinitionHolder里面的beanDifinition注册到了beanFactory中
3.4 BeanDefinitionParserDelegate
BeanDefinitionParserDelegate类最终调用了方法
AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean)
用来解析<bean>节点:
……..设置bean的属性 //处理解析<bean>下面的各子标签 //<meta>子标签 parseMetaElements(ele, bd); //<lookup-method>子标签 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //<replaced-method>子标签 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //<constructor-arg>子标签 parseConstructorArgElements(ele, bd); //<property>子标签 parsePropertyElements(ele, bd); bd.setResourceDescription(this.readerContext.getResource().getDescription()); bd.setSource(extractSource(ele)); return bd; |
在此方法内部实现了解析bean节点及其下的所有子标签,并返回AbstractBeanDefinition对象。
在解析<property>元素的value时,有对value属性,ref属性,idref属性及value标签下的各种子标签<ref>,<idref>,<bean>,<list>,<map>,<set>,<props>,<null>等进行处理,其中ref,idref属性及标签将返回RuntimeBeanReference对象,内部<bean>将递归地进行处理,并最终返回AbstractBeanDefinition对象,<list>、 <map>、<set>、<props>将对应地返回ManagedList, ManagedMap, ManagedSet, ManagedProperties对象并返回TypedStringValue对象,<null>标签将返回null,value属性或value字符串将返回TypedStringValue对象。
四、 所使用到的工具类
在此过程中所使用到的一些工具类和主要方法如下:
org.springframework.beans.BeanUtils类:其内部的重载方法instantiateClass()将通过反射创建对象
org.springframework.util.CollectionUtils类:其提供了操作集合的一些有用的工具方法
org.springframework.util.ObjectUtils类:提供了操作对象的工具方法、主要包括判断数组是否为空、添加元素至数组中、给定类型的数组变为Object数组、null安全情况下的equals比较、null安全情况下对象,数组等变为字符串
org.springframework.util.SystemPropertyUtils类:用系统属性值替换字符串中的占位符参数
org.springframework.core.io.support. PropertiesLoaderUtils类:用于根据资源名或资源流加载java.util.Properties对象