美文网首页Spring源码
BeanDefinition的Resource定位分析

BeanDefinition的Resource定位分析

作者: KingdomCoder | 来源:发表于2020-04-24 10:22 被阅读0次
    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.
         * <p>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定位分析

        本文链接:https://www.haomeiwen.com/subject/smyxwhtx.html