Spring 4.x BeanFactory 源码分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

我们在之前的文章简单的介绍了BeanFactory,现在看下源码。

启动

我们看下之前的代码

    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    // 获取xml文件。生成Resource
    Resource res = resolver.getResource("classpath:resource/spring-config.xml");
    // 创建DefaultListableBeanFactory对象
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    // 初始化BeanFactory
    reader.loadBeanDefinitions(res);

Resource —— getResource

这里实现的是:PathMatchingResourcePatternResolver类的getResource

        /**
        * Return the ResourceLoader that this pattern resolver works with.
         */
        public ResourceLoader getResourceLoader() {
            return this.resourceLoader;
        }
        @Override
        public Resource getResource(String location) {
            return getResourceLoader().getResource(location);
        }

new DefaultListableBeanFactory();

        /**
         * Create a new DefaultListableBeanFactory.
         */
        public DefaultListableBeanFactory() {
            super();
        }
        /**
         * Create a new AbstractAutowireCapableBeanFactory.
         */
        public AbstractAutowireCapableBeanFactory() {
            super();
            ignoreDependencyInterface(BeanNameAware.class);
            ignoreDependencyInterface(BeanFactoryAware.class);
            ignoreDependencyInterface(BeanClassLoaderAware.class);
        }
        /**
         * Create a new AbstractBeanFactory.
         */
        public AbstractBeanFactory() {
        }

我们可以看到不仅仅是创建了一个DefaultListableBeanFactory对象,同时还创建了:AbstractAutowireCapableBeanFactory,AbstractBeanFactory两个对象。

new XmlBeanDefinitionReader(factory);

        /**
         * Create new XmlBeanDefinitionReader for the given bean factory.
         * @param registry the BeanFactory to load bean definitions into,
         * in the form of a BeanDefinitionRegistry
         */
        public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
            super(registry);
        }
        // 父类
        protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
            this.registry = registry;

            // Determine ResourceLoader to use.
            if (this.registry instanceof ResourceLoader) {
                this.resourceLoader = (ResourceLoader) this.registry;
            }
            else {
                this.resourceLoader = new PathMatchingResourcePatternResolver();
            }

            // Inherit Environment if possible
            if (this.registry instanceof EnvironmentCapable) {
                this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
            }
            else {
                this.environment = new StandardEnvironment();
            }
        }

loadBeanDefinitions

        /**
         * Load bean definitions from the specified XML file.
         * @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
         */
        @Override
        public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
            return loadBeanDefinitions(new EncodedResource(resource));
        }

下面是重载的方法

        /**
         * Load bean definitions from the specified XML file.
         * @param encodedResource the resource descriptor for the XML file,
         * allowing to specify an encoding to use for parsing the file
         * @return the number of bean definitions found
         * @throws BeanDefinitionStoreException in case of loading or parsing errors
         */
        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 {
                InputStream inputStream = encodedResource.getResource().getInputStream();
                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    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();
                }
            }
        }

其实可以看成两部分代码
第一部分:

            // 如果资源文件不是空的话,
            Assert.notNull(encodedResource, "EncodedResource must not be null");
            // 判断是否启用了信息日志记录
            if (logger.isInfoEnabled()) {
                logger.info("Loading XML bean definitions from " + encodedResource.getResource());
            }
            // 将资源设置为当前Resource
            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 {
            // 将Resource还原为InputStream流。
                InputStream inputStream = encodedResource.getResource().getInputStream();
                try {
                // 再将InputStream流转换为InputSource — 对XML实体的一个单个输入源
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    // 核心方法:doLoadBeanDefinitions。
                    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

        /**
         * Actually load bean definitions from the specified XML file.
         * 实际上从指定的XML文件加载bean定义。
         * @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 {
                Document doc = doLoadDocument(inputSource, resource);
                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);
            }
        }

其中核心代码为:

                // 将资源文件转成Document对象
                Document doc = doLoadDocument(inputSource, resource);
                // 将Document对象注册成为Bean。
                return registerBeanDefinitions(doc, resource);

看下Document对象:

Document

我们看下Document接口介绍

    package org.w3c.dom;

    /**
     * The <code>Document</code> interface represents the entire HTML or XML
     * document. Conceptually, it is the root of the document tree, and provides
     * the primary access to the document's data.
     * 
     * 翻译:
     * Document接口代表全部的 HTML 或者 XML文件。
     * 概念上,他是整个文件树的根,同时给文件的数据提供最主要的入口。
     */

同时要确定一点,Document接口是W3C的,并不是Spring的。

看下registerBeanDefinitions方法:

registerBeanDefinitions

        /**
         * Register the bean definitions contained in the given DOM document.
         * 注册包含在给定DOM文档中的bean定义。
         * Called by {@code loadBeanDefinitions}.
         * <p>Creates a new instance of the parser class and invokes
         *  。。。
         * 返回发现bean定义的数目
         * @return the number of bean definitions found
         * 。。。
         */
        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            // 获取BeanDefinitionDocumentReader对象
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            // 返回注册表中定义的bean的数目。
            int countBefore = getRegistry().getBeanDefinitionCount();
            // 更新BeanDefinitionDocumentReader对象
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }

两个主要的方法:createBeanDefinitionDocumentReaderregisterBeanDefinitions
createBeanDefinitionDocumentReader

        /**
         * Create the {@link BeanDefinitionDocumentReader} to use for actually
         * reading bean definitions from an XML document.
         * <p>The default implementation instantiates the specified "documentReaderClass".
         * @see #setDocumentReaderClass
         * 翻译:
         * 创建BeanDefinitionDocumentReader,用于实际读取XML文档中的bean定义。
         * <P>默认实现实例化指定的“DopeCudieCrar类”。
         */
        protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
            return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
        }

registerBeanDefinitions

    /**
         * This implementation parses bean definitions according to the "spring-beans" XSD
         * (or DTD, historically).
         * <p>Opens a DOM Document; then initializes the default settings
         * specified at the {@code <beans/>} level; then parses the contained bean definitions.
         * 翻译:
         * 此实现根据“Spring Bean”XSD(或DTD,历史上)解析bean定义。
         * <p>打开DOM文档;然后初始化在该级别指定的默认设置;然后解析包含的bean定义。
         */
        @Override
        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            logger.debug("Loading bean definitions");
            Element root = doc.getDocumentElement();
            doRegisterBeanDefinitions(root);
        }

来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring 4.x BeanFactory 源码分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏