BeanDefinition的Resource定位分析

1.概述

通过源码我们发现,资源的定位问题主要发生在容器初始化过程中完成的,FileSystemXmlApplicationContextClassPathXmlApplicationContext 在一个构造器函数中执行refresh()容器启动的过程中完成的,当然这边启动过程中容器会有大量的复杂的初始化操作,资源的定位只是其中的一小环节。下面我们就FileSystemXmlApplicationContext 为例介绍Resource资源定位过程分析。

2.ApplicationContext集成体系介绍

ApplicationContext集成体系

这里我们需要重点关注的是AbstractRefreshableApplicationContext的refreshBeanFactory方法的实现,refreshBeanFactory()方法被FileSystemXmlApplicationContext构造函数中的refresh()调用。在这个方法中,通过createBeanFactory()构建了一个IoC容器供ApplicationContext使用。这个IoC容器就是我们前面提到过的DefaultListableBeanFactory,同时,它启动了loadBeanDefinitions()来载入BeanDefinition,这个过程和前面以编程的方式来使用IoC容器(XmlBeanFacoty)的过程非常类似。

3.源码分析:

我们就资源定位和加载的核心代码拿出来分析:


    /**
     * This implementation performs an actual refresh of this context's underlying
     * bean factory, shutting down the previous bean factory (if any) and
     * initializing a fresh bean factory for the next phase of the context's lifecycle.
     */
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        /// 这里判断,如果已经建立了BeanFactory,则销毁并关闭该BeanFactory
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 这里是创建并设置持有的DefaultListableBeanFactory的地方
           // 同时调用loadBeanDefinitions载入BeanDefinition的信息
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            // 资源就是在此处定位并加载的
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

我们找到loadBeanDefinitions(beanFactory)方法,此方法中完成了资源的定位和加载,主要执行如下代码:

protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
            throws BeansException, IOException;

我们可以看到在AbstractRefreshableApplicationContext抽象类中它只是提供了一个抽象的模板方法,具体实现由不同的子类去覆盖实现,这边我们主要是通过FileSystemXmlApplicationContext为例分析,所以我们找到相关的实现是在AbstractXmlApplicationContext中去实现的:

    /**
     * Loads the bean definitions via an XmlBeanDefinitionReader.
     * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
     * @see #initBeanDefinitionReader
     * @see #loadBeanDefinitions
     */
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        // 为相应的BeanFactory创建XmlBeanDefinitionReader(后续xml元信息的解析就依靠此类完成)
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        // 环境变量设置
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        // 设置ResourceLoader,这边传this是因为在容器继承链中是继承了DefaultResourceLoader的
        // AbstractApplicationContext 继承了DefaultResourceLoader
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        // 加载资源
        loadBeanDefinitions(beanDefinitionReader);
    }

AbstractXmlApplicationContext#loadBeanDefinitions(beanDefinitionReader)方法中实现了真正的资源定位和加载:


    /**
     * Load the bean definitions with the given XmlBeanDefinitionReader.
     * 

The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory} * method; hence this method is just supposed to load and/or register bean definitions. * @param reader the XmlBeanDefinitionReader to use * @throws BeansException in case of bean registration errors * @throws IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver */ protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { // 获取子类覆盖实现的资源 Resource[] configResources = getConfigResources(); // 加载资源 if (configResources != null) { reader.loadBeanDefinitions(configResources); } // 获取子类中设置的资源数组的资源路径URL String[] configLocations = getConfigLocations(); //实现加载 if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }

从代码中我们可以看到String[] configLocations = getConfigLocations(); 资源路径的获取是在这边调用的,如果子类覆盖可此实现,那么我们直接可以从子类中获取到相应的资源文件。反过来看我们从FileSystemXmlApplicationContext中去看,在FileSystemXmlApplicationContext中确实是覆盖了getConfigLocations();方法。

微信公众号

你可能感兴趣的:(BeanDefinition的Resource定位分析)