spring源码分析-XmlBeanFactory导读

 2019-11-23 11:11  阅读(1005)
文章分类:Spring Cloud

本文以spring框架的XmlBeanFactory为入手点进行分析,只讲解了如何加载bean定义这块,希望能够以尽量简洁明了的方式给予有需要的朋友一定的帮助。

首先来打开该类的代码,我们将看到如下代码:

以下内容为程序代码:publicclassXmlBeanFactoryextendsDefaultListableBeanFactory{  privatefinalXmlBeanDefinitionReaderreader=newXmlBeanDefinitionReader(this);  publicXmlBeanFactory(Resourceresource)throwsBeansException{    this(resource,null);  }  publicXmlBeanFactory(Resourceresource,BeanFactoryparentBeanFactory)throwsBeansException{    super(parentBeanFactory);    this.reader.loadBeanDefinitions(resource);  }}
以下内容为程序代码:publicclassXmlBeanFactoryextendsDefaultListableBeanFactory{  privatefinalXmlBeanDefinitionReaderreader=newXmlBeanDefinitionReader(this);  publicXmlBeanFactory(Resourceresource)throwsBeansException{    this(resource,null);  }  publicXmlBeanFactory(Resourceresource,BeanFactoryparentBeanFactory)throwsBeansException{    super(parentBeanFactory);    this.reader.loadBeanDefinitions(resource);  }}

这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最重要的地方在于最后一个构造函数:

以下内容为程序代码:   super(parentBeanFactory);  this.reader.loadBeanDefinitions(resource);
以下内容为程序代码:   super(parentBeanFactory);  this.reader.loadBeanDefinitions(resource);

第一句就是将父亲工厂交给父类的构造函数,实际上最后也就是把父工厂保存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。第二句就是整个类中最重要的地方了,顾名思义,它的目的是通过XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的配置文件)读取bean的定义。接下来我们打开XmlBeanDefinitionReader的loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用的loadBeanDefinitions方法,这个方法里最主要的部分就是:

以下内容为程序代码:       InputSourceinputSource=newInputSource(inputStream);        if(encodedResource.getEncoding()!=null){          inputSource.setEncoding(encodedResource.getEncoding());        }    returndoLoadBeanDefinitions(inputSource,encodedResource.getResource());
以下内容为程序代码:       InputSourceinputSource=newInputSource(inputStream);        if(encodedResource.getEncoding()!=null){          inputSource.setEncoding(encodedResource.getEncoding());        }    returndoLoadBeanDefinitions(inputSource,encodedResource.getResource());

这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法

DocumentBuilderFactory factory = createDocumentBuilderFactory();

if (logger.isDebugEnabled()) {

logger.debug(“Using JAXP implementation [” + factory + “]”);

}

DocumentBuilder builder = createDocumentBuilder(factory);

Document doc = builder.parse(inputSource);

return registerBeanDefinitions(doc, resource);

这个方法的目的一目了然,就是为了将资源解释成为Document对象,然后调用registerBeanDefinitions方法,这里不做详细解释,不了解的话请去看看关于JAXP的介绍。接下来我们打开registerBeanDefinitions方法:

以下内容为程序代码:  publicintregisterBeanDefinitions(Documentdoc,Resourceresource)throwsBeansException{    XmlBeanDefinitionParserparser=        (XmlBeanDefinitionParser)BeanUtils.instantiateClass(this.parserClass);    returnparser.registerBeanDefinitions(this,doc,resource);  }
以下内容为程序代码:  publicintregisterBeanDefinitions(Documentdoc,Resourceresource)throwsBeansException{    XmlBeanDefinitionParserparser=        (XmlBeanDefinitionParser)BeanUtils.instantiateClass(this.parserClass);    returnparser.registerBeanDefinitions(this,doc,resource);  }

这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类是DefaultXmlBeanDefinitionParser,这个接口很简单,只有registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们看到如下代码:

以下内容为程序代码:  publicintregisterBeanDefinitions(BeanDefinitionReaderreader,Documentdoc,Resourceresource)      throwsBeanDefinitionStoreException{    this.beanDefinitionReader=reader;    this.resource=resource;    logger.debug(“Loadingbeandefinitions”);    Elementroot=doc.getDocumentElement();    //初始化根元素    initDefaults(root);    if(logger.isDebugEnabled()){      logger.debug(“Defaultlazyinit‘”+getDefaultLazyInit()+“‘”);      logger.debug(“Defaultautowire‘”+getDefaultAutowire()+“‘”);      logger.debug(“Defaultdependencycheck‘”+getDefaultDependencyCheck()+“‘”);    }    preProcessXml(root);//一个空方法用于扩展    intbeanDefinitionCount=parseBeanDefinitions(root);//解释配置的主要方法    if(logger.isDebugEnabled()){      logger.debug(“Found”+beanDefinitionCount+”<bean>elementsin”+resource);    }    postProcessXml(root);//一个空方法用于扩展    returnbeanDefinitionCount;  }
以下内容为程序代码:  publicintregisterBeanDefinitions(BeanDefinitionReaderreader,Documentdoc,Resourceresource)      throwsBeanDefinitionStoreException{    this.beanDefinitionReader=reader;    this.resource=resource;    logger.debug(“Loadingbeandefinitions”);    Elementroot=doc.getDocumentElement();    //初始化根元素    initDefaults(root);    if(logger.isDebugEnabled()){      logger.debug(“Defaultlazyinit‘”+getDefaultLazyInit()+“‘”);      logger.debug(“Defaultautowire‘”+getDefaultAutowire()+“‘”);      logger.debug(“Defaultdependencycheck‘”+getDefaultDependencyCheck()+“‘”);    }    preProcessXml(root);//一个空方法用于扩展    intbeanDefinitionCount=parseBeanDefinitions(root);//解释配置的主要方法    if(logger.isDebugEnabled()){      logger.debug(“Found”+beanDefinitionCount+”<bean>elementsin”+resource);    }    postProcessXml(root);//一个空方法用于扩展    returnbeanDefinitionCount;  }

在这个方法当中,主要用于解释定义的有两个方法,一个是initDefaults,一个是parseBeanDefinitions,第一个方法是用来解释根元素的属性的,例如lazy-init, autowire等,而parseBeanDefinitions就是用来解释具体的bean定义了,方法代码如下:

以下内容为程序代码:  protectedintparseBeanDefinitions(Elementroot)throwsBeanDefinitionStoreException{    NodeListnl=root.getChildNodes();    intbeanDefinitionCount=0;    for(inti=0;i<nl.getLength();i++){      Nodenode=nl.item(i);      if(nodeinstanceofElement){        Elementele=(Element)node;        if(IMPORT_ELEMENT.equals(node.getNodeName())){          importBeanDefinitionResource(ele);        }        elseif(ALIAS_ELEMENT.equals(node.getNodeName())){          Stringname=ele.getAttribute(NAME_ATTRIBUTE);          Stringalias=ele.getAttribute(ALIAS_ATTRIBUTE);          this.beanDefinitionReader.getBeanFactory().registerAlias(name,alias);        }        elseif(BEAN_ELEMENT.equals(node.getNodeName())){          beanDefinitionCount++;          BeanDefinitionHolderbdHolder=parseBeanDefinitionElement(ele,false);          BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,this.beanDefinitionReader.getBeanFactory());        }      }    }    returnbeanDefinitionCount;  }
以下内容为程序代码:  protectedintparseBeanDefinitions(Elementroot)throwsBeanDefinitionStoreException{    NodeListnl=root.getChildNodes();    intbeanDefinitionCount=0;    for(inti=0;i<nl.getLength();i++){      Nodenode=nl.item(i);      if(nodeinstanceofElement){        Elementele=(Element)node;        if(IMPORT_ELEMENT.equals(node.getNodeName())){          importBeanDefinitionResource(ele);        }        elseif(ALIAS_ELEMENT.equals(node.getNodeName())){          Stringname=ele.getAttribute(NAME_ATTRIBUTE);          Stringalias=ele.getAttribute(ALIAS_ATTRIBUTE);          this.beanDefinitionReader.getBeanFactory().registerAlias(name,alias);        }        elseif(BEAN_ELEMENT.equals(node.getNodeName())){          beanDefinitionCount++;          BeanDefinitionHolderbdHolder=parseBeanDefinitionElement(ele,false);          BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,this.beanDefinitionReader.getBeanFactory());        }      }    }    returnbeanDefinitionCount;  }

其他标签具体如何被解释这里就不多说,相信大家也能看得懂,这里主要讲一下解释bean的的处理,我们注意以下代码:

以下内容为程序代码:               elseif(BEAN_ELEMENT.equals(node.getNodeName())){          beanDefinitionCount++;          BeanDefinitionHolderbdHolder=parseBeanDefinitionElement(ele,false);          BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,this.beanDefinitionReader.getBeanFactory());        }
以下内容为程序代码:               elseif(BEAN_ELEMENT.equals(node.getNodeName())){          beanDefinitionCount++;          BeanDefinitionHolderbdHolder=parseBeanDefinitionElement(ele,false);          BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,this.beanDefinitionReader.getBeanFactory());        }

这里是当碰到一个bean标签的时候所进行的处理,也既是对bean的定义进行解释,可以看到parseBeanDefinitionElement方法的第一个参数就是bean则个元素,第二个参数表示该bean是否为内置的bean,从这里进行解释的bean都不可能是内置的,所以这里直接以false为参数,打开parseBeanDefinitionElement方法,就可以看到这个方法里就是对bean的内部的解释,也很简单,也不多讲了,呵呵(下班时间已经到了,所以就写这么多了,基本的流程也就这样,没什么特别难的地方。),对了,最后还有一点就是解释完后,bean的定义将会被保存到beanFactory中,这个beanFactory的实现就是XmlBeanFactory了,该beanFactory是在new的时候被传递到reader中的,就是该类中以下这行代码:

以下内容为程序代码:  privatefinalXmlBeanDefinitionReaderreader=newXmlBeanDefinitionReader(this);
以下内容为程序代码:  privatefinalXmlBeanDefinitionReaderreader=newXmlBeanDefinitionReader(this);

补充:

我们看到XmlBeanFactory使用了DefaultListableBeanFactory作为它持有的IOC容器实现,在这个基础上,添加了XML形式的Bean定义信息的读取功能。从这个角度看,这个

DefaultListableBeanFactory是很重要的一个Spring IOC实现。下面我们可以看到上下文也和XmlBeanFactory一样,通过持有这个DefaultListableBeanFactory来获得基本的IOC容器的功能。通过编程式的使用DefaultListableBeanFactory我们可以看到IOC容器使用的一些基本过程:

ClassPathResource res = new ClassPathResource(“beans.xml”);

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(res);

这些代码演示了以下几个步骤:

  1. 创建IOC配置文件的抽象资源
  2. 创建一个BeanFactory,这里我们使用DefaultListableBeanFactory
  3. 创建一个载入bean定义信息的读取器,这里使用XmlBeanDefinitionReader来载入XML形式的bean定义信息,配置给BeanFactory
  4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成,这样完成整个载入和注册bean定义的过程。我们的IoC容器就建立起来

这个基本过程我们可以看到,IOC容器建立的基本步骤,这些我们可以编程式的完成这些配置,但在Spring中,它提供的上下文已经为我们作了这些事情,所以从这个角度说上下文是一个高级形态上的IOC容器。更方便了用户的使用,相比于那些基本的IOC容器的BeanFactory实现,上下文除了提供基本的上面看到的容器的基本功能外,还为用户提供了以下的附加服务更方便的让客户使用容器:

• 可以支持不同的信息源,我们看到ApplicationContext扩展了MessageSource

• 访问资源, 体现在对ResourceLoader和Resource的支持上面,这样我们可以从不同地方得到bean定义资源,这样用户程序可以灵活的定义Bean定义信息

• 支持应用事件,继承了接口ApplicationEventPublisher,这样在上下文中引入了事件机制而

BeanFactory没有在上下文环境中,这些上下文提供的基础服务更丰富了基本IOC容器的功能。所以一般我们建议客户使用上下文作为IOC容器来使用 – 和XmlBeanFactory一样,上下文是通过持有DefaultListableBeanFactory这个基本的IOC容器实现来提供IOC容器的基本功能的,这一点可以在下面我们分析IOC容器的初始化过程中看得很清楚。

我们看到XmlBeanFactory使用了DefaultListableBeanFactory作为它持有的IOC容器实现,在这个基础上,添加了XML形式的Bean定义信息的读取功能。从这个角度看,这个

DefaultListableBeanFactory是很重要的一个Spring IOC实现。下面我们可以看到上下文也和XmlBeanFactory一样,通过持有这个DefaultListableBeanFactory来获得基本的IOC容器的功能。通过编程式的使用DefaultListableBeanFactory我们可以看到IOC容器使用的一些基本过程:

ClassPathResource res = new ClassPathResource(“beans.xml”);

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(res);

这些代码演示了以下几个步骤:

  1. 创建IOC配置文件的抽象资源
  2. 创建一个BeanFactory,这里我们使用DefaultListableBeanFactory
  3. 创建一个载入bean定义信息的读取器,这里使用XmlBeanDefinitionReader来载入XML形式的bean定义信息,配置给BeanFactory
  4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成,这样完成整个载入和注册bean定义的过程。我们的IoC容器就建立起来

这个基本过程我们可以看到,IOC容器建立的基本步骤,这些我们可以编程式的完成这些配置,但在Spring中,它提供的上下文已经为我们作了这些事情,所以从这个角度说上下文是一个高级形态上的IOC容器。更方便了用户的使用,相比于那些基本的IOC容器的BeanFactory实现,上下文除了提供基本的上面看到的容器的基本功能外,还为用户提供了以下的附加服务更方便的让客户使用容器:

• 可以支持不同的信息源,我们看到ApplicationContext扩展了MessageSource

• 访问资源, 体现在对ResourceLoader和Resource的支持上面,这样我们可以从不同地方得到bean定义资源,这样用户程序可以灵活的定义Bean定义信息

• 支持应用事件,继承了接口ApplicationEventPublisher,这样在上下文中引入了事件机制而

BeanFactory没有在上下文环境中,这些上下文提供的基础服务更丰富了基本IOC容器的功能。所以一般我们建议客户使用上下文作为IOC容器来使用 – 和XmlBeanFactory一样,上下文是通过持有DefaultListableBeanFactory这个基本的IOC容器实现来提供IOC容器的基本功能的,这一点可以在下面我们分析IOC容器的初始化过程中看得很清楚。


来源:http://ddrv.cn/a/88268

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> spring源码分析-XmlBeanFactory导读

相关推荐