关于spring:Spring源码分析spring源码之obtainFreshBeanFactory介绍

4次阅读

共计 5236 个字符,预计需要花费 14 分钟才能阅读完成。

1. 前言

2.spring 源码 obtainFreshBeanFactory()介绍

3. 总结

1. 前言

github 源码地址(带正文):
https://github.com/su15967456…

咱们上篇博客对 spring 的外围办法有了一个大略的认知,从今往后的几篇博客,咱们将会将这几个办法进行深刻地剖析。

话不多说,先上图。

明天咱们要介绍的 obtainFreshBeanFactory()办法,其次要性能就是:
1. 创立容器对象 DefaultListableBeanFactory
2. 加载各种配置文件的属性到以后工厂中,最重要的就是封装成 BeanDefinition

2.spring 源码 obtainFreshBeanFactory()介绍

接下来咱们来剖析一下这个办法,首先往这个办法里点击:

    /**
     * Tell the subclass to refresh the internal bean factory.
     * @return the fresh BeanFactory instance
     * @see #refreshBeanFactory()
     * @see #getBeanFactory()
     */
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 初始化 BeanFactory, 并进行 xml 文件读取,并将失去的 BeanFactory 记录在以后实体的属性中
        refreshBeanFactory();
        return getBeanFactory();// 返回以后实体的 beanFactory 属性}

正文上通知咱们:次要就是生成一个 bean 工厂,咱们能够持续察看 refreshBeanFactory()办法。

/**
     * 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 {
        // 如果有 bean 工厂了,先销毁掉
        if (hasBeanFactory()) {destroyBeans();
            closeBeanFactory();}
        try {
            // 创立 DefaultListableBeanFactory 对象
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            // 每个容器都有本人的 id,为了序列化指定 id,能够从 id 反序列化到 beanFactory 对象
            beanFactory.setSerializationId(getId());
            // 定制 beanFactory,设置相干属性,包含是否容许笼罩同名称的不同定义的对象以及循环依赖, 能够通过子类重写
            customizeBeanFactory(beanFactory);
            // 初始化 documentReader,并进行对 xml 文件进行解析
            loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        }
        catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for" + getDisplayName(), ex);
        }
    }

咱们能够高深莫测地看到,这个办法的前几步是非常简略而明了的:
1. 创立一个 bean 工厂对象
2. 设置一下容器的 id
3. 设置一下 beanFactory 的相干属性(包含是否容许笼罩同名称的不同定义的对象以及循环依赖, 能够通过子类重写)如果不分明括号内容也没关系,次要就是有些属性当前要用到,咱们这里要先进行一下初始化
4. 对 xml 文件进行解析(这是一个封装办法,咱们还要往里面持续查看,看看 spring 是如何将 xml 文件读取到容器中的)

咱们持续 debug,进入 loadBeanDefinitions(beanFactory)办法;

/**
     * 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.
        // 适配器模式
        // 创立一个 xml 的 beanDefinitionReader,并通过回调设置到 beanFactory 中
        //beanFactory 和 applicationContext 没有方法间接读取 xml,就交给 beanDefinitionReader 进行,这就是适配器模式
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        // 给 reader 对象设置环境对象
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        // 设置一个 entity,用它来读取本地的 xsd 或者 dtd 文件,来实现相干的解析工作
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        // 设计模式,适配器模式
        // 初始化 beanDefinitionReader 对象,此处设置配置文件是否须要验证
        initBeanDefinitionReader(beanDefinitionReader);
        // 开始实现 beanDefinition 的加载
        loadBeanDefinitions(beanDefinitionReader);
    }

能够看出,大略进行了如下的操作:
创立一个 XmlBeanDefinitionReader,通过 XmlBeanDefinitionReader 来实现 beanDefinition 的加载
这里应用了适配器模式:就是 beanFactory 自身没方法进行 xml 文件(配置文件)的读取,所以要借助 beanDefinitionReader 类进行对配置文件的读取,要让 beanDefinitionReader 做一个适配。(就像手机没方法间接从插座中获取电源,要借助适配器来充电。)
所以把 beanFactory 交给 beanDefinitionReader,让 beanDefinitionReader 读取文件,封装成 beanDefinition,退出 beanFactory 容器中。

/**
     * Actually load bean definitions from the specified XML file.
     * @param inputSource the SAX InputSource to read from
     * @param resource the resource descriptor for the XML file
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of loading or parsing errors
     * @see #doLoadDocument
     * @see #registerBeanDefinitions
     */
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {

        try {
            // 此处获取 xml 文件的 document 对象,这个解析过程是由 documentLoader 实现的,// 从 string[] -> StringResources -> resources
            // 最终将 resources 解析成一个个 document 文档,依据文档信息封装成 BeanDefinition 对象
            Document doc = doLoadDocument(inputSource, resource);
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {logger.debug("Loaded" + count + "bean definitions from" + resource);
            }
            return count;
        } 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);
        }
    }

而后咱们始终往 loadBeanDefinitions(beanDefinitionReader); 里 debug,会发现两个办法:
1.doLoadDocument(inputSource, resource);
2.registerBeanDefinitions(doc, resource);

留神,spring 外面 do 结尾的办法才是做实事的办法
这里先加载了一下文件,而后再创立了一下 beanDefinition 并且往 factory 注册了一下。至于具体的业务逻辑,能够先不去看,因为咱们看源码的工夫不是很长,咱们大略晓得流程就能够了,拘泥于细节的旋涡可能会劝退。

3. 总结
明天咱们大略总结了一下 obtainFreshBeanFactory()办法,该办法次要有两个作用:

1. 创立容器对象 DefaultListableBeanFactory
2. 加载各种配置文件的属性到以后工厂中,封装成 BeanDefinition

正文完
 0