zoukankan      html  css  js  c++  java
  • Bean Definition从加载、解析、处理、注册到BeanFactory的过程。

    为了弄清楚Bean是怎么来的,花费了大把功夫,现在要把Bean Definition的加载、解析、处理、注册到bean工厂的过程记下来。这只是bean definition 的加载、解析、处理、注册过程中的一种。

      好记性不如烂笔头。

    首先我已经知道bean definition 存在了哪里:它就存在一个Map对象中,如果使用的是DefaultListableBeanFactory的话,它就存在一个ConcurrentHashMap对象中。

        /** bean 的名字为键,BeanDefinition为值,初始容量为256 */
        private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

    现在将BeanDefinition是如何一步步走到这个Map对象中的。

    一、BeanDefinition的加载

    过程比较长,得对着源码慢慢看。

    这里讲的是使用xml配置文件的方式来配置bean.

    既然是使用的xml配置文件的方式来配置bean,那么首先要读取xml文件。

    一)、AbstractBeanDefinitionReader类中

    这一步只是说加载bean definition,但是这里方法参数resources 所指的资源并不确定是什么样的,有可能是xml文件,也有可能是属性文件,或者是脚本。

        @Override
        public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
            Assert.notNull(resources, "Resource array must not be null");
            int counter = 0;
            for (Resource resource : resources) {
                counter += loadBeanDefinitions(resource);//这个方法有几个实现,如下
            }
            return counter;
        }

    上面的代码中的一行 counter += loadBeanDefinitions(resource); 这行代码有好几个实现类都实现了它。如下图:

    我这里使用实现类XmlBeanDefinitionReader中的实现,所以这里的资源是xml文件。

    二)、XmlBeanDefinitionReader类中

    从指定的xml文件中加载bean definition,但是他这里只是将Resource转化为EncodedResource对象。然后把这个任务递交给它的重载方法来做。

    三)、XmlBeanDefinitionReader类中

    从指定的XML文件中加载bean definition。但还不是真正的加载bean定义,只是做准备。

        /**
         * 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();
                }
            }
        }

    四、XmlBeanDefinitionReader类中

    这里是真正的从xml 文件中加载的bean definition 。主要有两个步骤:①、加载指定的文档,得到一个Document对象。②、将Document对象和Resource交给registerBeanDefinitions(...)方法来完成注册

        /**
         * 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 {
                Document doc = doLoadDocument(inputSource, resource);
                return registerBeanDefinitions(doc, resource);
            }
            catch (BeanDefinitionStoreException ex) {
                //省略捕获异常的代码
            }
        }

    五)、XmlBeanDefinitionReader类中

    注册指定的Document对象中的bean definition。这里实际上是创建了一个BeanDefinitionDocumentReader对象然后让它来完成。

        /**
         * Register the bean definitions contained in the given DOM document.
         * Called by {@code loadBeanDefinitions}.
         * <p>Creates a new instance of the parser class and invokes
         * {@code registerBeanDefinitions} on it.
         * @param doc the DOM document
         * @param resource the resource descriptor (for context information)
         * @return the number of bean definitions found
         * @throws BeanDefinitionStoreException in case of parsing errors
         * @see #loadBeanDefinitions
         * @see #setDocumentReaderClass
         * @see BeanDefinitionDocumentReader#registerBeanDefinitions
         */
        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            int countBefore = getRegistry().getBeanDefinitionCount();
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
            return getRegistry().getBeanDefinitionCount() - countBefore;
        }

    二、BeanDefinition的解析

    六)、DefaultBeanDefinitionDocumentReader类中

    DefaultBeanDefinitionDocumentReader是BeanDefinitionDocumentReader的一个实现类。这一步主要是解析文档解析的是<beans/>。比如xml文件是XSD的还是DTD的。

    这里主要是获得一个Element对象。这个对象就代表xml文件中的<beans/>节点。在这个节点下包含着文件中的所有<bean/>节点。然后将这个Element对像交给的doRegistrerBeanDefinitions(Element)方法来处理。

    七)、DefaultBeanDefinitionDocumentReader类中

    这个方法将</beans>节点下的每一个<bean/>相对应的bean definition注册。但是真正做这件事的是另一个方法 parseBeanDefinitions(root, this.delegate);

    不过在调用parseBeanDefinitions(root,this.delegate)方法之前和之后都可以对这个这个方法参数中的Element对象进行处理。

        /**
         * Register each bean definition within the given root {@code <beans/>} element.
         */
        protected void doRegisterBeanDefinitions(Element root) {
            // Any nested <beans> elements will cause recursion in this method. In
            // order to propagate and preserve <beans> default-* attributes correctly,
            // keep track of the current (parent) delegate, which may be null. Create
            // the new (child) delegate with a reference to the parent for fallback purposes,
            // then ultimately reset this.delegate back to its original (parent) reference.
            // this behavior emulates a stack of delegates without actually necessitating one.
            BeanDefinitionParserDelegate parent = this.delegate;
            this.delegate = createDelegate(getReaderContext(), root, parent);
    
            if (this.delegate.isDefaultNamespace(root)) {
                String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
                if (StringUtils.hasText(profileSpec)) {
                    String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                            profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                    if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                    "] not matching: " + getReaderContext().getResource());
                        }
                        return;
                    }
                }
            }
    
            preProcessXml(root);
            parseBeanDefinitions(root, this.delegate);
            postProcessXml(root);
    
            this.delegate = parent;
        }

    八、DefaultBeanDefinitionDocumentReader类中

    用一个for循环遍历<beans/>节点下的所有子节点,也就是所有的<bean/>,然后对<bean/>节点进行解析。注意,刚才是对<beans/>进行解析。不过这个解析的任务交给parseDefaultElement(Element ele,BeanDefinitionParserDelegate delegate)方法来完成。

    九)、DefaultBeanDefinitionDocumentReader类中

    这个方法用到了递归,因为bean是可以嵌套的,所以<beans/>节点下的每一个<bean/>节点都可能在嵌套有很多bean。所以它会判断这个bean是不是嵌套bean,如果不是就进行处理,如果是就进行递归。

    处理bean元素的任务交给了三个方法,如图。我这里用processBeanDefinition(ele,delegate)方法举例。

    三、BeanDefinition的处理

    十)、DefaultBeanDefinitionDocumentReader类中

    在这个方法中它将的Element对象转化成了BeanDefinitionHolder对象。这个BeanDefinitionHolder对象中持有的BeanDefinition实例的引用,还有beanName,还有bean的别名。

    然后将BeanDefinitionHolder对象和特定的bean工厂作为参数交个BeanDefinitionReaderUtils类来处理来进行注册。

    第301行代码中如何创建BeanDefinitionHolder的??BeanDefinition的创建

    四、BeanDefinition的注册

    十一)、BeanDefinitionReaderUtils类中

    这个方法先根据BeanDefinitionHolder获取beanName和BeanDefinition,然后将其注册到Bean工厂中Map对象中。比如bean工厂是DefaultListableBeanFactory。

    上面红色方框中的代码 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());这个方法有好几个实现类实现了它,如下图:

    我选择了DefaultListableBeanFactory

    十二)、DefaultListableBeanFactory类中,在这个方法中,将BeanDefinition 注册到了开头所说的ConcurrentHashMap对象中了。

        //---------------------------------------------------------------------
        // Implementation of BeanDefinitionRegistry interface
        //---------------------------------------------------------------------
    
        @Override
        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionStoreException {
    
            Assert.hasText(beanName, "Bean name must not be empty");
            Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
            if (beanDefinition instanceof AbstractBeanDefinition) {
                try {
                    ((AbstractBeanDefinition) beanDefinition).validate();
                }
                catch (BeanDefinitionValidationException ex) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Validation of bean definition failed", ex);
                }
            }
    
            BeanDefinition oldBeanDefinition;
    
            oldBeanDefinition = this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) {
                if (!isAllowBeanDefinitionOverriding()) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
                }
                else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                    // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                                "' with a framework-generated bean definition: replacing [" +
                                oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
                else if (!beanDefinition.equals(oldBeanDefinition)) {
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding bean definition for bean '" + beanName +
                                "' with a different definition: replacing [" + oldBeanDefinition +
                                "] with [" + beanDefinition + "]");
                    }
                }
                else {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Overriding bean definition for bean '" + beanName +
                                "' with an equivalent definition: replacing [" + oldBeanDefinition +
                                "] with [" + beanDefinition + "]");
                    }
                }
                this.beanDefinitionMap.put(beanName, beanDefinition);
            }
            else {
                if (hasBeanCreationStarted()) {
                    // Cannot modify startup-time collection elements anymore (for stable iteration)
                    synchronized (this.beanDefinitionMap) {
                        this.beanDefinitionMap.put(beanName, beanDefinition);
                        List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                        updatedDefinitions.addAll(this.beanDefinitionNames);
                        updatedDefinitions.add(beanName);
                        this.beanDefinitionNames = updatedDefinitions;
                        if (this.manualSingletonNames.contains(beanName)) {
                            Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                            updatedSingletons.remove(beanName);
                            this.manualSingletonNames = updatedSingletons;
                        }
                    }
                }
                else {
                    // Still in startup registration phase
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    this.beanDefinitionNames.add(beanName);
                    this.manualSingletonNames.remove(beanName);
                }
                this.frozenBeanDefinitionNames = null;
            }
    
            if (oldBeanDefinition != null || containsSingleton(beanName)) {
                resetBeanDefinition(beanName);
            }
        }

    五、总结

    BeanDefinition的加载、解析、处理、注册主要涉及到了四个类。
    ①、XMLBeanDefinitionReader:主要是的任务是把XML文件加载到内存中以Document对象的形式存在。
    ②、DefaultBeanDefinitionDocumentReader:完成解析和处理的任务。最后将处理得到的BeanDefinitionHolder交给了BeanDefinitionReaderUtils进行注册。
    ③、BeanDefinitionReaderUtils:BeanDefinitionHolder有了,Bean工厂也有了,它就负责把BeanDefinitionHolder中的BeanDefinition和BeanName等取出来,然后注册到Bean工厂中。

    ④、DefaultListableBeanFactory(bean工厂):它有一个ConcurrentHashMap成员变量,以beanName为键,BeanDefinition为值保存注册的bean。

  • 相关阅读:
    管理者的存在 说明了企业文化的匮乏【20140124】
    Sublime Text2(ST2)点滴积累及使用技巧_持续更新【20130320】【最近修改20130516】
    WebStorm 点滴积累及使用技巧_持续更新【20130323】【最近修改20130604】
    码农,企业,和资本
    关于赛车游戏的一点体会
    从艺感悟
    三种糟糕的程序员
    关于ios单机盗版
    汽车加速性,功率和扭矩
    ExtJS之面向对象的概念
  • 原文地址:https://www.cnblogs.com/GooPolaris/p/8169611.html
Copyright © 2011-2022 走看看