您的位置:首页 > 编程语言 > Java开发

Spring学习笔记---2.1-IOC容器解析Bean配置信息

2016-01-12 11:49 861 查看


在上一节中我们知道了Spring启动时Bean的类与容器之间关系,也知道它们之间的加载顺序。

接下来我想弄明白的是:
           1、当我配置了XML配置文件,和Bean类的信息,启动Spring时容器是怎么去读取Bean的配置信息的?
           2、Spring容器中的Bean定义注册表是什么定义? 
           3、容器是怎么根据Bean注册表实例化Bean的?
           4、容器又是如何将Bean实例放到Spring容器中的?
           5、Bean缓冲池是什么样的概念?
           6、应用程序在用户点击时怎么通过什么样的机制使用Bean的?

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
先回答第一个问题:当我配置了XML配置文件,和Bean类的信息,启动Spring时容器是怎么去读取Bean的配置信息的?
         我们先来看看XML文件的配置:
          


            图中非常清晰的标示出来了这个类的id和class的意义。
        配置了XML之后,Spring容器是怎么得到Bean的信息的:通过容器的getBean("foo")即可获取对应的Bean,在容器中起到定位查找的作用,是外部程序和SpringIOC容器进行交互的桥梁。class属性指定了Bean对应的实现类。
        那么Spring容器是如何通过getBean("foo")方法得到其对应的Bean的呢?还有就是通过那个类或者接口的方法得到Bean的信息的?
        通过上面的一节我们知道了容器中最基础的有BeanFactory,继承自BeanFactory,提供完整功能的有ApplicationContext。
        但是还在使用XML文件配置Bean的依赖关系的其实使用的XMLBeanFactory。
            


     
        Spring 使用XmlBeanDefinitionReader 来读取并解析 xml 文件, 
        XmlBeanDefinitionReader 是BeanDefinitionReader 接口的实现。
        BeanDefinitionReader  定了spring 读取bean 定义的一个接口,这个接口中有一些loadBeanDefinitions 方法,从他们的方法签名可知,spring
把读取 bean 配置的来源抽象为Resource 接口。下图是BeanDefinitionReader  类中的一个loadBeanDefinitions()方法,该类中重载了很多这个方法。
         
             BeanDefinitionReader   接口中有两个具体的实现,其中之一就是从xml文件中读取配置的 XmlBeanDefinitionReader ,另一个则是从java
properties 文件中读取配置的 PropertiesBeanDefinitionReader。
       
       在XmlBeanFactory中创建了XMLBeanDefinitionReader 的实例,并在XmlBeanFactory
的构造方法中调用了 XmlBeanDefinitionReader 的loadBeanDefinitions方法,由 loadBeanDefinitions 方法负责加载bean 配置并把bean配置注册到XMLBeanFactory中。    

        其实际流转过程是:XMLBeanFactory 是使用XmlBeanDefinitionReader来读取XML文件的。而实际这个读取转发到XMLBeanDefinitionReader 的loadBeanDefinitions方法。

       public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
       ……
      private DocumentLoader documentLoader = new DefaultDocumentLoader();

      public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(new EncodedResource(resource));
     }

     public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
     ……
     try {
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
   ……
   }

  protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            int validationMode = getValidationModeForResource(resource);
            Document doc = this.documentLoader.loadDocument(
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
            return registerBeanDefinitions(doc, resource);
        }
    ……
   }
    ……
 }

     loadBeanDefinitions方法首先要通过Resource 接口读取 xml 配置文件,并把它读到一个 Document 对象中,进行解析,这个动作是由接口 DocumentLoader 的实现来完成的。spring有一个默认实现 DefaultDocumentLoader。
     
    至于在DefaultDocumentLoader 类中如何实现的,有兴趣的朋友可以去看一下:

    public class DefaultDocumentLoader implements DocumentLoader {

    @Override
    public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        return builder.parse(inputSource);
    }

    protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
            throws ParserConfigurationException {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(namespaceAware);

        if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
            factory.setValidating(true);
            if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
                // Enforce namespace aware for XSD...
                factory.setNamespaceAware(true);
                try {
                    factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
                }
                catch (IllegalArgumentException ex) {
                    ParserConfigurationException pcex = new ParserConfigurationException(
                            "Unable to validate using XSD: Your JAXP provider [" + factory +
                            "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
                            "Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
                    pcex.initCause(ex);
                    throw pcex;
                }
            }
        }

        return factory;
    }

    protected DocumentBuilder createDocumentBuilder(
            DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler)
            throws ParserConfigurationException {

        DocumentBuilder docBuilder = factory.newDocumentBuilder();
        if (entityResolver != null) {
            docBuilder.setEntityResolver(entityResolver);
        }
        if (errorHandler != null) {
            docBuilder.setErrorHandler(errorHandler);
        }
        return docBuilder;
    }
}

 在完成了 Resource 到 Document 的转换后,下面就是从 Document 中解析出各个 bean 的配置了,为此spring 又抽象了一个接口 BeanDefinitionDocumentReader,从它的名称中可以一目了然这个接口负责从Document 中读取 bean 定义,这个接口中只定义了一个方法 registerBeanDefinitions。spring 也提供了一个默认实现 DefaultBeanDefinitionDocumentReader。
        
      OK,到此容器算是读取到了配置文件的内容;
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

在下一篇文章中研究SpringIOC 的内部工作机制,不再贴源码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息