Spring IOC-XmlBeanFactory如何加载xml及如何存储转换后的信息

来源:互联网 发布:淘宝账号自助开通网址 编辑:程序博客网 时间:2024/05/16 04:35

本文主要介绍我们定义的xml配置文件是怎样被Spring加载封装到bean工厂的。
我们写代码使用Spring的IOC通常是这样的:

  Resource resource=new FileSystemResource("benas-config.xml");   BeanFactory factory=new XmlBeanFactory(resource);   HelloBean hello=(HelloBean)factory.getBean("helloBean");   System.out.println(hello.getHelloWord()); 

配置文件通常是这样的

<bean id="helloBean" class="spring2.HelloBean">     <property name="helloWord">         <value>hello</value>     </property> </bean></beans> 

那么我们就直接看底层代码是怎么实现的,转到XmlBeanFactory中,在这个类构造的时候就会去读取我们传入的xml文件,像这样:

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {    super(parentBeanFactory);    this.reader.loadBeanDefinitions(resource);}

那么我们自然转到XmlBeanDefinitionReader类中的实现代码:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {    try {             //转换为输入流                                                                               InputStream inputStream = encodedResource.getResource().getInputStream();            try {             //构造InputSource                                                                               InputSource inputSource = new InputSource(inputStream);                              if (encodedResource.getEncoding() != null) {                             inputSource.setEncoding(encodedResource.getEncoding());                          }                 //把xml中的bean的定义解析出来                                                                               return doLoadBeanDefinitions(inputSource, encodedResource.getResource());        }                                                                                    finally {                                                                                inputStream.close();                                                             }                                                                                }                                                                                

转到doLoadBeanDefinitions(InputSource inputSource, Resource resource)中,主要代码如下:

………………try {                                                                                                      int validationMode = getValidationModeForResource(resource);        //调用[com.sun.org.apache.xerces.internal    //.jaxp.DocumentBuilderImpl.parse(inputSource)]解析为Document对象                                       Document doc = this.documentLoader.loadDocument(                                                               inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());      return registerBeanDefinitions(doc, resource);                                                     }                                                                                                      ………………

在转到registerBeanDefinitions方法:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {              BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();                                documentReader.setEnvironment(this.getEnvironment());                                                              int countBefore = getRegistry().getBeanDefinitionCount();                                                          //注册当前解析到的bean到工厂,注意这里会初始化“读环境”,初始化换进过的时候会将当前的beanFactory的对象引用传入,这样以后这个环境里就维持了一个到工厂的引用                             documentReader.registerBeanDefinitions(doc, createReaderContext(resource));//在这里报错                                 return getRegistry().getBeanDefinitionCount() - countBefore;//DefaultBeanDefinitionDocumentReader              }                                                                                                                  

注意这里的BeanDefinitionDocumentReader对象实际为DefaultBeanDefinitionDocumentReader(作用完成bean的定义读取和封装到bean工厂),然后看这个类:

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {    protected void doRegisterBeanDefinitions(Element root) {        preProcessXml(root);        //实际的解析过程        parseBeanDefinitions(root, this.delegate);        postProcessXml(root);    } }

然后我们在把代码定位到parseBeanDefinitions方法,因为要贴的代码有点多,这里就截图了:
这里写图片描述
图上注释说的很清楚,这个解析的过程是用Spring定义的一套标签的解析类来完成的,每一个标签都对应自己的解析类,这里要注意几个特殊的标签,是没有解析类的,它们是alias、name、import和bean,对于这四个标签,Spring直接调用在DefaultBeanDefinitionDocumentReader中的方法解析。
具体解析过程我们以标签为例说明(最终的解析封装过程在BeanDefinitionParserDelegate类中)。

这里写图片描述
我们看到一些列的解析,最终构造出了AbstractBeanDefinition类,就是说bean工厂在读取配置文件之后是转换为了一系列的AbstractBeanDefinition类,然后在工厂会判断一个bean定义的是不是单例的,如果是单例的那么就会实例化,如果不是单例的,是发生在用户第一次请求的时候实例化。

0 0
原创粉丝点击