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