2-Spring源码解析之默认标签的解析(1)

Spring中的标签包括【默认标签】和【自定义标签】两种。
在这里插入图片描述
默认标签的解析是在 DefaultBeanDefinitionDocumentReader 类的 parseDefaultNamespace 方法中进行。

我们先来看一下parseDefaultNamespace方法的具体实现。

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    	// 对 import 标签的处理
        if (delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        } 
        // 对 alias 标签的处理
        else if (delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        } 
		// 对 bean 标签的处理
		else if (delegate.nodeNameEquals(ele, "bean")) {
            this.processBeanDefinition(ele, delegate);
        } 
		// 对 beans 标签的处理
		else if (delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }
    }

一、bean标签的解析及注册

在这4中标签中,bean 标签的解析最为重要和复杂,因此我们先分析 bean 标签的解析。

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    	// --------------- 1.1 具体讲解---------------步骤【1】
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
        // --------------- 1.2 具体讲解---------------步骤【2】
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
        // --------------- 1.3 具体讲解---------------步骤【3】
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }
		// --------------- 1.4 具体讲解---------------步骤【4】
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

其中参数Element ele是从 Document 中获取的(Element root = doc.getDocumentElement();)。

上述方法的整体逻辑如下:

  • 【1】委托BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法进行元素解析和信息提取,返回BeanDefinitionHolder类型的实例bdHolder,此时bdHolder实例一斤包含了我们的配置文件中的各个属性了。如:class、name、id、alias等属性。
  • 【2】当返回的bdHolder实例不为空的时候,如果存在默认标签的子节点下面再有自定义属性,还需要再次对自定义标签进行解析
  • 【3】对解析后的bdHolder进行注册。
  • 【4】最后发出响应事件,通知相关的监听器,这个bean已经家在完毕。

下面我们就将具体分析上述4个步骤的具体实现过程。

1.1 解析 BeanDefinition

首先分析BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

进入BeanDefinitionParserDelegate类的parseBeanDefinitionElement(ele)方法。

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
        return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
    }
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    	// 解析 id 属性
        String id = ele.getAttribute("id");
        // 解析 name 属性
        String nameAttr = ele.getAttribute("name");
        // 分割 name 属性
        List<String> aliases = new ArrayList();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
            beanName = (String)aliases.remove(0);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            this.checkNameUniqueness(beanName, aliases, ele);
        }
		// --------------- 1.1.1 具体讲解---------------解析其他的属性
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            if (!StringUtils.hasText(beanName)) {
                try {
                	// 如果不存在 beanName name 根据 spring 中提供的命名规则为当前 bean 生产对应的 beanName
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    } else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            // 将 BeanDefinition 的信息存储到 BeanDefinitionHolder 中
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }

上面代码中只有对 id 和 name 的解析,其他属性的解析在 AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean); 中。我们先看一下上述代码的逻辑:

  • 【1】提取元素中的 id 以及 name 属性
  • 【2】解析其他所有属性病同意封装到 GenericBeanDefinition 类型的实例中
  • 【3】如果检测到 bean 没有制定 beanName,name使用默认规则为此Bean生成 beanName
  • 【4】将获取到的信息封装到 BeanDefinitionHolder
1.1.1 解析其他属性 parseBeanDefinitionElement
    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        // 解析 class 属性
        if (ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }

        try {
            String parent = null;
            // 解析 parent 属性
            if (ele.hasAttribute("parent")) {
                parent = ele.getAttribute("parent");
            }
			
			// 创建用于承载属性的 AbstractBeanDefinition 类型的 GenericBeanDefinition
			// 下面具体分析
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            // 硬编码解析默认 bean 的各种属性
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            // 提取 description
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            // 解析元数据
            this.parseMetaElements(ele, bd);
            // 解析 lookup-method 属性
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            // 解析 replaced-method 属性
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			// 解析构造函数参数
            this.parseConstructorArgElements(ele, bd);
            // 解析property子元素
            this.parsePropertyElements(ele, bd);
            // 解析 qualifier 子元素
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

        return null;
    }

【1】创建用于属性承载的 BeanDefinition

BeanDefinition 是一个接口,是配置文件<bean> 元素标签在容器中的内部形式。<bean> 元素标签拥有 class、scope、lazy-init 等配置属性, BeanDefinition 则提供了相应的 beanClass、scope、lazyInit属性, BeanDefinition<bean> 元素标签中的属性是一一对应的。其中 RootBeanDefinition 是最常用的实现类,它对应一般性的<bean> 元素标签。

Spring 通过 BeanDefinition 将配置文件中的<bean> 元素标签配置信息转换为容器的内部表示,并将这些 BeanDefinition 注册到BeanDefinitionRegistry 中。 Spring容器的 BeanDefinitionRegistry 就像是Spring配置信息的内部数据库,主要是以map的形式保存,后续操作直接从 BeanDefinitionRegistry 中读取配置信息。
在这里插入图片描述
要解析属性首先要创建承载属性的实例,也就是创建 GenericBeanDefinition 类型的实例。

    protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException {
        return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());
    }
    public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
        GenericBeanDefinition bd = new GenericBeanDefinition();
        // parentName 可能为空
        bd.setParentName(parentName);
        if (className != null) {
            if (classLoader != null) {
            	// 如果classLoader不为空,则使用以传入的classLoader同一虚拟机加载类对象,否则只是记录className
                bd.setBeanClass(ClassUtils.forName(className, classLoader));
            } else {
                bd.setBeanClassName(className);
            }
        }
        return bd;
    }

创建完成创建用于承载bean信息的实例对象:GenericBeanDefinition 后,我们进入this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);方法,对元素属性进行具体分析。

    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
    	// 解析 singleton 属性
        if (ele.hasAttribute("singleton")) {
            this.error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
        } else if (ele.hasAttribute("scope")) {
            bd.setScope(ele.getAttribute("scope"));
        } else if (containingBean != null) {
            bd.setScope(containingBean.getScope());
        }

        if (ele.hasAttribute("abstract")) {
            bd.setAbstract("true".equals(ele.getAttribute("abstract")));
        }

        String lazyInit = ele.getAttribute("lazy-init");
        if ("default".equals(lazyInit)) {
            lazyInit = this.defaults.getLazyInit();
        }

        bd.setLazyInit("true".equals(lazyInit));
        String autowire = ele.getAttribute("autowire");
        bd.setAutowireMode(this.getAutowireMode(autowire));
        String dependencyCheck = ele.getAttribute("dependency-check");
        bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck));
        String autowireCandidate;
        if (ele.hasAttribute("depends-on")) {
            autowireCandidate = ele.getAttribute("depends-on");
            bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
        }

        autowireCandidate = ele.getAttribute("autowire-candidate");
        String destroyMethodName;
        if (!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) {
            bd.setAutowireCandidate("true".equals(autowireCandidate));
        } else {
            destroyMethodName = this.defaults.getAutowireCandidates();
            if (destroyMethodName != null) {
                String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
                bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
            }
        }

        if (ele.hasAttribute("primary")) {
            bd.setPrimary("true".equals(ele.getAttribute("primary")));
        }

        if (ele.hasAttribute("init-method")) {
            destroyMethodName = ele.getAttribute("init-method");
            if (!"".equals(destroyMethodName)) {
                bd.setInitMethodName(destroyMethodName);
            }
        } else if (this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }

        if (ele.hasAttribute("destroy-method")) {
            destroyMethodName = ele.getAttribute("destroy-method");
            bd.setDestroyMethodName(destroyMethodName);
        } else if (this.defaults.getDestroyMethod() != null) {
            bd.setDestroyMethodName(this.defaults.getDestroyMethod());
            bd.setEnforceDestroyMethod(false);
        }

        if (ele.hasAttribute("factory-method")) {
            bd.setFactoryMethodName(ele.getAttribute("factory-method"));
        }

        if (ele.hasAttribute("factory-bean")) {
            bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
        }
        return bd;
    }

【2】解析子元素 constructor-arg

  • this.parseConstructorArgElements(ele, bd);
    public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
        NodeList nl = beanEle.getChildNodes();

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            // 解析子元素 `constructor-arg`
            if (this.isCandidateElement(node) && this.nodeNameEquals(node, "constructor-arg")) {
                this.parseConstructorArgElement((Element)node, bd);
            }
        }

    }
    public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
    	// 提取 index 属性
        String indexAttr = ele.getAttribute("index");
        // 提取 type 属性
        String typeAttr = ele.getAttribute("type");
        // 提取 name 属性
        String nameAttr = ele.getAttribute("name");
        if (StringUtils.hasLength(indexAttr)) {
            try {
                int index = Integer.parseInt(indexAttr);
                if (index < 0) {
                    this.error("'index' cannot be lower than 0", ele);
                } else {
                    try {
                        this.parseState.push(new ConstructorArgumentEntry(index));
                        // 解析 ele 对应的属性元素
                        Object value = this.parsePropertyValue(ele, bd, (String)null);
                        // 用来封装解析出来的数据
                        ValueHolder valueHolder = new ValueHolder(value);
                        if (StringUtils.hasLength(typeAttr)) {
                            valueHolder.setType(typeAttr);
                        }

                        if (StringUtils.hasLength(nameAttr)) {
                            valueHolder.setName(nameAttr);
                        }

                        valueHolder.setSource(this.extractSource(ele));
                        // 不允许重复指定相同的参数
                        if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                            this.error("Ambiguous constructor-arg entries for index " + index, ele);
                        } else {
                            bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
                        }
                    } finally {
                        this.parseState.pop();
                    }
                }
            } catch (NumberFormatException var19) {
                this.error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
            }
        }
        // 没有 index 属性则忽略其属性,自动寻找 
        else {
            try {
                this.parseState.push(new ConstructorArgumentEntry());
                Object value = this.parsePropertyValue(ele, bd, (String)null);
                ValueHolder valueHolder = new ValueHolder(value);
                if (StringUtils.hasLength(typeAttr)) {
                    valueHolder.setType(typeAttr);
                }

                if (StringUtils.hasLength(nameAttr)) {
                    valueHolder.setName(nameAttr);
                }

                valueHolder.setSource(this.extractSource(ele));
                bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
            } finally {
                this.parseState.pop();
            }
        }

    }
1.1.2 AbstractBeanDefinition 属性

至此,我们完成了对 XML文档到 GenericBeanDefinition 的转换。 即,XML中所有的配置都可以在 GenericBeanDefinition的实例类中找到对应的配置。

GenericBeanDefinition 只是子类实现,在上面图中可以看到,GenericBeanDefinition类的父类是AbstractBeanDefinition,大部分的通用属性都保存在了AbstractBeanDefinition中。

1.2 解析默认标签中的自定义标签元素decorateBeanDefinitionIfRequired

    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
        return this.decorateBeanDefinitionIfRequired(ele, definitionHolder, (BeanDefinition)null);
    }
    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
        BeanDefinitionHolder finalDefinition = definitionHolder;
        NamedNodeMap attributes = ele.getAttributes();
		// 遍历所有的属性,看看是否有适用于修饰的属性
        for(int i = 0; i < attributes.getLength(); ++i) {
            Node node = attributes.item(i);
            // ------下面具体讲解------------
            finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd);
        }

        NodeList children = ele.getChildNodes();
		
		// 遍历所有的子节点,看看是否有适用于修饰的子元素
        for(int i = 0; i < children.getLength(); ++i) {
            Node node = children.item(i);
            if (node.getNodeType() == 1) {
                finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd);
            }
        }

        return finalDefinition;
    }
    public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
    	// 获取自定义标签的命名空间
        String namespaceUri = this.getNamespaceURI(node);
        // 对于非默认标签进行修饰
        if (!this.isDefaultNamespace(namespaceUri)) {
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if (handler != null) {
            	// 根据命名空间找到对应的处理器
                return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
            }

            if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
                this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
            }
        }

        return originalDef;
    }

decorateBeanDefinitionIfRequired中,我们可以看到对于程序默认的标签的处理其实是直接略过的,因为默认的标签到这里已经被处理完了,这里只对自定义的标签或者说对bean的自定义属性感兴趣。在方法中实现了寻找自定义标签并根据自定义标签寻找命名空间处理器,并进行进一步的解析。

BeanDefinitionHolder 类的内容

public class BeanDefinitionHolder implements BeanMetadataElement {
    private final BeanDefinition beanDefinition;
    private final String beanName;
    private final String[] aliases;
}

1.3 注册解析的BeanDefinition

在这里插入图片描述

    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
    	// 使用 beanName 做唯一标识注册
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
		
		// 注册所有的别名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                registry.registerAlias(beanName, alias);
            }
        }

    }

从上面代码可以看出,解析的 BeanDefinition 都会被注册到 BeanDefinitionRegistry 类型的实例 registry 中,而对于 beanDefinition 的注册分为两个部分:

  • 通过beanName注册
  • 通过别名注册
1.3.1 通过 beanName 注册
    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 var9) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);
            }
        }

        BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        // 如果对应的 beanName 已经注册且在配置中配置了bean不允许被覆盖,则抛出异常。
        if (oldBeanDefinition != null) {
            if (!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
            }

            if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                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 (this.hasBeanCreationStarted()) {
                synchronized(this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            } else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || this.containsSingleton(beanName)) {
            this.resetBeanDefinition(beanName);
        }

    }

二、总结

本文讲解的内容主要分清楚以下三个概念:

  • BeanDefinition
  • BeanDefinitionHolder
  • BeanDefinitionRegistry
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值