Spring Ioc(4)——web中BeanDefinition的载入

来源:互联网 发布:网络教育的收费标准 编辑:程序博客网 时间:2024/05/08 04:09
我们继续上一节,其实spring Ioc的实现从宏观上看,分为三步:
(1)BeanDefinition的载入
(2)BeanDefinition的解析
(3)BeanDefinition的注册
1、BeanDefinition载入的入口
那么分别一个一个来分析,先从载入入手。BeanDefinition的载入,就相当于把我们定义的BeanDefinition在IOC容器中表示成spring内部的数据结构的过程,BeanDefinition在Spring容器中是用HashMap来维护的。我们同样的从入口着手,看其实如何实现载入的。
上一节我们谈到了WebApplicationContext的构建,在其构建完毕后,便调用了AbstractApplicationContext的refresh方法,其实这也是BeanDefinition载入的入口。从图中可以看到AbstractApplicationContext是XmlWebApplicationContext的基类。

refresh是很重要的一个方法,描述了整个初始化的过程,其中有一段代码通知子类去refresh BeanFactory,那么我们来看看AbstractRefreshableApplicationContext的核心代码:
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
                        //构建一个DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
                        //启动beanDefinition的载入
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
代码中构建了一个DefaultListableBeanFactory,并且启动了beanDefinition的载入,具体的载入实现是在XmlWebApplicationContext中实现的。
2、BeanDefinition载入的过程
我们从上面的源代码就可以看到,在XmlWebApplicationContext中,通过方法loadBeanDefinition启动了载入,实际上载入的过程是在XmlBeanDefinitionReader中完成的。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
                      //获取xml文件和io的InputSource
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                             //启动BeanDefiniton的载入
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

我们再来看调用的doLoadBeanDefinitions方法:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            int validationMode = getValidationModeForResource(resource);
            //获取xml文件的Document对象,完成载入BeanDefinition。
            Document doc = this.documentLoader.loadDocument(
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
                            //BeanDefinition的解析(后面继续讨论)
            return registerBeanDefinitions(doc, resource);
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }
原创粉丝点击