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

本文主要介绍我们定义的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>hellovalue> 
    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 IOC-XmlBeanFactory如何加载xml及如何存储转换后的信息_第1张图片
图上注释说的很清楚,这个解析的过程是用Spring定义的一套标签的解析类来完成的,每一个标签都对应自己的解析类,这里要注意几个特殊的标签,是没有解析类的,它们是alias、name、import和bean,对于这四个标签,Spring直接调用在DefaultBeanDefinitionDocumentReader中的方法解析。
具体解析过程我们以标签为例说明(最终的解析封装过程在BeanDefinitionParserDelegate类中)。

Spring IOC-XmlBeanFactory如何加载xml及如何存储转换后的信息_第2张图片
我们看到一些列的解析,最终构造出了AbstractBeanDefinition类,就是说bean工厂在读取配置文件之后是转换为了一系列的AbstractBeanDefinition类,然后在工厂会判断一个bean定义的是不是单例的,如果是单例的那么就会实例化,如果不是单例的,是发生在用户第一次请求的时候实例化。

你可能感兴趣的:(Spring,IOC)