zoukankan      html  css  js  c++  java
  • spring源码阅读(二) Bean加载之默认标签加载

    接着上文的内容,我们经历了xml资源文件的校验/解析/终于要进入到Bean的加载中了。

    上文进行到:

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            if (delegate.isDefaultNamespace(root)) {
                NodeList nl = root.getChildNodes();
    
                for(int i = 0; i < nl.getLength(); ++i) {
                    Node node = nl.item(i);
                    if (node instanceof Element) {
                        Element ele = (Element)node;
                        if (delegate.isDefaultNamespace(ele)) {
                            this.parseDefaultElement(ele, delegate);
                        } else {
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            } else {
                delegate.parseCustomElement(root);
            }
    
        }

    这里,加载代理类的一个判断是否是默认命名空间的标签,把过程分为两个步骤,我们先来看第一个分支,即默认标签的解析。

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
            if (delegate.nodeNameEquals(ele, "import")) {
                this.importBeanDefinitionResource(ele);
            } else if (delegate.nodeNameEquals(ele, "alias")) {
                this.processAliasRegistration(ele);
            } else if (delegate.nodeNameEquals(ele, "bean")) {
                this.processBeanDefinition(ele, delegate);
            } else if (delegate.nodeNameEquals(ele, "beans")) {
                this.doRegisterBeanDefinitions(ele);
            }
    
        }

    默认的这几个根标签的解析,我们就从最关注的"bean"标签解析开始吧。即:this.processBeanDefinition(ele, delegate)。

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);   //  1
            if (bdHolder != null) {
                bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); // 2
    
                try {
                    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry()); // 3
                } catch (BeanDefinitionStoreException var5) {
                    this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
                }
    
                this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); // 4
            }
    
        }

    这里分为几个步骤:

    1: 把ele元素解析为我们需要的 BeanDefinitionHolder 对象。

    2: 判断子元素中,是否有自定义标签,如果有调用自定义标签的处理Handle进行处理,并获取返回的bdHolder

    3: 将解析到的bdHolder注册到我们的配置读取上下文的注册表中

    4: 触发Bean注册完成的事件通知

    理完思路,那我们就从第一个步骤开始,即把ele xml节点翻译成我们的BeanDefinition对象。

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
            String id = ele.getAttribute("id");
            String nameAttr = ele.getAttribute("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);
            }
    
            AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
            if (beanDefinition != null) {
                if (!StringUtils.hasText(beanName)) {
                    try {
                        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);
                return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
            } else {
                return null;
            }
        }

    这里首先获取AbstractBeanDefinition对象,然后组装成BeanDefinitionHolder。查看parseBeanDefinitionElement 的代码

    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
            this.parseState.push(new BeanEntry(beanName));
            String className = null;
            if (ele.hasAttribute("class")) {
                className = ele.getAttribute("class").trim();
            }
    
            try {
                String parent = null;
                if (ele.hasAttribute("parent")) {
                    parent = ele.getAttribute("parent");
                }
    
                AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
                this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
                bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
                this.parseMetaElements(ele, bd);
                this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
                this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
                this.parseConstructorArgElements(ele, bd);
                this.parsePropertyElements(ele, bd);
                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;
        }

    看这句createBeanDefinition(className, parent),跟进代码到BeanDefinitionReaderUtils的createBeanDefinition方法

    public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
            GenericBeanDefinition bd = new GenericBeanDefinition();
            bd.setParentName(parentName);
            if (className != null) {
                if (classLoader != null) {
                    bd.setBeanClass(ClassUtils.forName(className, classLoader));
                } else {
                    bd.setBeanClassName(className);
                }
            }
    
            return bd;
        }

    这里创建的是一个GenericBeanDefinition对象。AbstractBeanDefinition一共有三个子类

    GenericBeanDefinition

    ChildBeanDefinition

    RootBeanDefinition

    暂时没看到Root和Child的应用,我们这里就只关注下这个GenericBeanDefinition。className不为空,classLoader为空,那么只设置下BeanCassName属性。

    继续解析:

    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
            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");
                if (!"".equals(destroyMethodName)) {
                    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;
        }

    这里解析各种bd的属性,并设置到bd对象里。这些属性比如init-method / destroy-method / lazy-init 这些我们经常使用的,还有些不熟悉的,可以到时候用到的时候查看了解下。

    下面解析META元素:

    public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
            NodeList nl = ele.getChildNodes();
    
            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (this.isCandidateElement(node) && this.nodeNameEquals(node, "meta")) {
                    Element metaElement = (Element)node;
                    String key = metaElement.getAttribute("key");
                    String value = metaElement.getAttribute("value");
                    BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
                    attribute.setSource(this.extractSource(metaElement));
                    attributeAccessor.addMetadataAttribute(attribute);
                }
            }
    
        }

    遍历所有meta标签,创建BeanMetaAttribute属性,并添加到bd中,这里向上转型到了BeanMetadataAttributeAccessor类。这里还是很清晰的,接口该做什么事情,还是分开的很清楚的。这里是架构设计里 接口隔离原则的体现。不同接口里,做的事情是不一样的,并不混在一起,这样当一个部分需要改动的时候,不会影响另一个部分。我的理解。

    继续:解析lookup-method元素

    public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
            NodeList nl = beanEle.getChildNodes();
    
            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (this.isCandidateElement(node) && this.nodeNameEquals(node, "lookup-method")) {
                    Element ele = (Element)node;
                    String methodName = ele.getAttribute("name");
                    String beanRef = ele.getAttribute("bean");
                    LookupOverride override = new LookupOverride(methodName, beanRef);
                    override.setSource(this.extractSource(ele));
                    overrides.addOverride(override);
                }
            }
    
        }

    添加到db的overrides属性里了。

    解析:replaced-method 根look-method标签类似不再赘述

    解析:constructor-arg 标签,构造函数标签比较常见,这里也相对复杂些,至少从代码上看

    public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
            NodeList nl = beanEle.getChildNodes();
    
            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (this.isCandidateElement(node) && this.nodeNameEquals(node, "constructor-arg")) {
                    this.parseConstructorArgElement((Element)node, bd);
                }
            }
    
        }

    先遍历元素,然后具体的操作,由parseConstructorArgElement方法来负责

    public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
            String indexAttr = ele.getAttribute("index");
            String typeAttr = ele.getAttribute("type");
            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));
                            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);
                }
            } 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();
                }
            }
    
        }

    先获取index/type/name属性,然后根据有没有index属性类分别处理

    如果有index属性,那么获取value,并创建valueHolder最终添加到constructorArgumentValues 中。

    来看具体的获取value的过程

    public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
            String elementName = propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
            NodeList nl = ele.getChildNodes();
            Element subElement = null;
    
            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (node instanceof Element && !this.nodeNameEquals(node, "description") && !this.nodeNameEquals(node, "meta")) {
                    if (subElement != null) {
                        this.error(elementName + " must not contain more than one sub-element", ele);
                    } else {
                        subElement = (Element)node;
                    }
                }
            }
    
            boolean hasRefAttribute = ele.hasAttribute("ref");
            boolean hasValueAttribute = ele.hasAttribute("value");
            if (hasRefAttribute && hasValueAttribute || (hasRefAttribute || hasValueAttribute) && subElement != null) {
                this.error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
            }
    
            if (hasRefAttribute) {
                String refName = ele.getAttribute("ref");
                if (!StringUtils.hasText(refName)) {
                    this.error(elementName + " contains empty 'ref' attribute", ele);
                }
    
                RuntimeBeanReference ref = new RuntimeBeanReference(refName);
                ref.setSource(this.extractSource(ele));
                return ref;
            } else if (hasValueAttribute) {
                TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));
                valueHolder.setSource(this.extractSource(ele));
                return valueHolder;
            } else if (subElement != null) {
                return this.parsePropertySubElement(subElement, bd);
            } else {
                this.error(elementName + " must specify a ref or value", ele);
                return null;
            }
        }

    获取value的过程分为几个主要部分,根据是ref类型,还是value类型不同,或者是子元素类型,操作不同

    如果是ref类型,创建RuntimeBeanReference对象;如果是value类型,则封装为TypedStringVlue类型。如果是子元素类型,则继续由parsePropertySubElement处理

    public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
            return this.parsePropertySubElement(ele, bd, (String)null);
        }
    
        public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
            if (!this.isDefaultNamespace((Node)ele)) {
                return this.parseNestedCustomElement(ele, bd);
            } else if (this.nodeNameEquals(ele, "bean")) {
                BeanDefinitionHolder nestedBd = this.parseBeanDefinitionElement(ele, bd);
                if (nestedBd != null) {
                    nestedBd = this.decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
                }
    
                return nestedBd;
            } else if (this.nodeNameEquals(ele, "ref")) {
                String refName = ele.getAttribute("bean");
                boolean toParent = false;
                if (!StringUtils.hasLength(refName)) {
                    refName = ele.getAttribute("local");
                    if (!StringUtils.hasLength(refName)) {
                        refName = ele.getAttribute("parent");
                        toParent = true;
                        if (!StringUtils.hasLength(refName)) {
                            this.error("'bean', 'local' or 'parent' is required for <ref> element", ele);
                            return null;
                        }
                    }
                }
    
                if (!StringUtils.hasText(refName)) {
                    this.error("<ref> element contains empty target attribute", ele);
                    return null;
                } else {
                    RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
                    ref.setSource(this.extractSource(ele));
                    return ref;
                }
            } else if (this.nodeNameEquals(ele, "idref")) {
                return this.parseIdRefElement(ele);
            } else if (this.nodeNameEquals(ele, "value")) {
                return this.parseValueElement(ele, defaultValueType);
            } else if (this.nodeNameEquals(ele, "null")) {
                TypedStringValue nullHolder = new TypedStringValue((String)null);
                nullHolder.setSource(this.extractSource(ele));
                return nullHolder;
            } else if (this.nodeNameEquals(ele, "array")) {
                return this.parseArrayElement(ele, bd);
            } else if (this.nodeNameEquals(ele, "list")) {
                return this.parseListElement(ele, bd);
            } else if (this.nodeNameEquals(ele, "set")) {
                return this.parseSetElement(ele, bd);
            } else if (this.nodeNameEquals(ele, "map")) {
                return this.parseMapElement(ele, bd);
            } else if (this.nodeNameEquals(ele, "props")) {
                return this.parsePropsElement(ele);
            } else {
                this.error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
                return null;
            }
        }

    这里可以看到,所有支持的子类的分类处理都有了,里边的具体内容,就感兴趣的进去看了。

    2019-07-01 15:11继续:

    构造函数元素的解析说完了,我们继续主线解析到db中的,property元素的解析

    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
            NodeList nl = beanEle.getChildNodes();
    
            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (this.isCandidateElement(node) && this.nodeNameEquals(node, "property")) {
                    this.parsePropertyElement((Element)node, bd);
                }
            }
    
        }
    public void parsePropertyElement(Element ele, BeanDefinition bd) {
            String propertyName = ele.getAttribute("name");
            if (!StringUtils.hasLength(propertyName)) {
                this.error("Tag 'property' must have a 'name' attribute", ele);
            } else {
                this.parseState.push(new PropertyEntry(propertyName));
    
                try {
                    if (!bd.getPropertyValues().contains(propertyName)) {
                        Object val = this.parsePropertyValue(ele, bd, propertyName);
                        PropertyValue pv = new PropertyValue(propertyName, val);
                        this.parseMetaElements(ele, pv);
                        pv.setSource(this.extractSource(ele));
                        bd.getPropertyValues().addPropertyValue(pv);
                        return;
                    }
    
                    this.error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
                } finally {
                    this.parseState.pop();
                }
    
            }
        }

    这里,跟构造函数的property元素解析不同的是,这里是构造了PropertyValue对象,并添加到bd的propertyValues里了。

    qualifier元素解析

    public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
            NodeList nl = beanEle.getChildNodes();
    
            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (this.isCandidateElement(node) && this.nodeNameEquals(node, "qualifier")) {
                    this.parseQualifierElement((Element)node, bd);
                }
            }
    
        }
    public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
            String typeName = ele.getAttribute("type");
            if (!StringUtils.hasLength(typeName)) {
                this.error("Tag 'qualifier' must have a 'type' attribute", ele);
            } else {
                this.parseState.push(new QualifierEntry(typeName));
    
                try {
                    AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
                    qualifier.setSource(this.extractSource(ele));
                    String value = ele.getAttribute("value");
                    if (StringUtils.hasLength(value)) {
                        qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
                    }
    
                    NodeList nl = ele.getChildNodes();
    
                    for(int i = 0; i < nl.getLength(); ++i) {
                        Node node = nl.item(i);
                        if (this.isCandidateElement(node) && this.nodeNameEquals(node, "attribute")) {
                            Element attributeEle = (Element)node;
                            String attributeName = attributeEle.getAttribute("key");
                            String attributeValue = attributeEle.getAttribute("value");
                            if (!StringUtils.hasLength(attributeName) || !StringUtils.hasLength(attributeValue)) {
                                this.error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
                                return;
                            }
    
                            BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
                            attribute.setSource(this.extractSource(attributeEle));
                            qualifier.addMetadataAttribute(attribute);
                        }
                    }
    
                    bd.addQualifier(qualifier);
                } finally {
                    this.parseState.pop();
                }
            }
        }

    构造Qualifier对象,并添加到bd的qualifier属性中。

    到这里,从ele文档元素到BeanDefinition对象的解析基本就完成了。

    我们梳理下大致的思路,其实就是解析各种元素,针对不同元素或是生成bd的属性,或是添加到对应的属性列表中,总之ele要完全转换成我们后续需要使用的BeanDefinition中。

    下面,做了这么多解析工作,我们来完整的看一下BeanDefinition的属性

    public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {
        public static final String SCOPE_DEFAULT = "";
        // 省略部分静态变量及final常量

    private String scope = SCOPE_DEFAULT; // bean的作用域范围,对应bean属性scope private boolean abstractFlag; // 是否是抽象,对应bean属性abstract private boolean lazyInit; // 是否延迟加载,对应bean属性lazy-init private int autowireMode; // 自动注入模式 AUTOWIRE_NO AUTOWIRE_BY_NAME AUTOWIRE_BY_TYPE AUTOWIRE_CONSTRUCTOR private int dependencyCheck; // 依赖检查,spring3.0后弃用 private String[] dependsOn; // 表示一个bean的实例化依靠另一个bean先实例化,对应bean的属性depend-on private boolean autowireCandidate; // autowireCandiate属性设置为false,这样容器在查找自动装配对象时,将不考虑该bean,即它不会考虑作为其他bean自动装配的候选者,但是该bean本身可以使用自动化装配来注入其他bean private boolean primary; // 自动装配时,如果出现多个bean候选者,将作为首选者,对应baen属性primary private final Map<String, AutowireCandidateQualifier> qualifiers; // 用于记录Qualifier,对应子元素qualifier private boolean nonPublicAccessAllowed; // 允许访问非公开的构造起和方法,程序设置 private boolean lenientConstructorResolution; // 是否以宽松模式解析构造函数,默认为true private ConstructorArgumentValues constructorArgumentValues; // 记录构造函数注入属性,对应bean属性constructor-arg private MutablePropertyValues propertyValues; // 普通属性集合 private MethodOverrides methodOverrides; // 方法重写持有者,记录lookup-method/ replace-method元素 private String factoryBeanName; // 用于bean属性factoryBean private String factoryMethodName; // 对应bean属性factory-method private String initMethodName; // 初始化方法,对应bean属性init-method private String destroyMethodName; // 销毁方法,对应bean属性destroy-method private boolean enforceInitMethod; // 是否执行init-method,程序设置 private boolean enforceDestroyMethod; // 是否执行destroy-method,程序设置 private boolean synthetic; // 是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true,程序设置 private int role; // 定义bean的应用,APPLICATION:用户/ INFRASTRUCTURE:完全内部使用,与用户无关/ SUPPORT某些复杂配置的一部分,程序设置 private String description; // bean描述信息 private Resource resource; // 这个bean定义的资源

    以上有些元素其实没怎么使用过,不是太熟悉,这些内容主要参考了《spring源码深度解析》- 郝佳著

    OK,我们回到之前bean解析的代码再来继续:

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
            if (bdHolder != null) {
                bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    
                try {
                    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
                } catch (BeanDefinitionStoreException var5) {
                    this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
                }
    
                this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
            }
    
        }

    我们之前重点都是在delegate.parseBeanDefinitionElement 的解析说明上,我们继续下边这句

    bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder) ,根据方法的名称,其实大概可以判断意思,如果有必要装饰BeanDefinition对象

    我们进入代码来看一下:

    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;
        }

     可以看到主要动作是,对属性及子元素进行处理,如果是默认元素,直接掠过,如果不是则根据命名空间,查找对应的处理handler进行解析处理,具体的解析过程暂时先放这里,后续再说。这里

    只介绍下做了什么事情。

    继续我们的核心步骤,该到注册步骤了,将我们的beanDefinition注册到注册表中。

    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
            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);
                }
            }
    
        }

    这里有两个部分,一个是根据beanName注册,一个是根据alias注册

    我们看第一个根据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 var4) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var4);
                }
            }
    
            BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) {
                if (!this.allowBeanDefinitionOverriding) {
                    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 (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else {
                this.beanDefinitionNames.add(beanName);  // 记录beanName
                this.manualSingletonNames.remove(beanName);
                this.frozenBeanDefinitionNames = null;
            }
    
            this.beanDefinitionMap.put(beanName, beanDefinition);
            if (oldBeanDefinition != null || this.containsSingleton(beanName)) {
                this.resetBeanDefinition(beanName); // 重置所有beanName对应的缓存
            }
    
        }

    这里还有一个校验,这里的校验主要校验的是methodOverrides,主要校验是否有这个类和这个类是否有相应的方法。

    这里的操作:

    1:校验,校验methodOverrides属性的正确性和有效性

    2:查看是否已经有了该beanName,如果有然后查看是否配置可覆盖,如果不是,直接抛出异常;如果设置可以覆盖,那么在后续的操作中覆盖掉即可

    3:加入map缓存

    4:清除解析前留下的beanName缓存

    继续:通过别名注册BeanDefinition

    public void registerAlias(String name, String alias) {
            Assert.hasText(name, "'name' must not be empty");
            Assert.hasText(alias, "'alias' must not be empty");
            if (alias.equals(name)) {
                this.aliasMap.remove(alias);
            } else {
                if (!this.allowAliasOverriding()) {
                    String registeredName = (String)this.aliasMap.get(alias);
                    if (registeredName != null && !registeredName.equals(name)) {
                        throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
                    }
                }
    
                this.checkForAliasCircle(name, alias);
                this.aliasMap.put(alias, name);
            }
    
        }

    步骤如下:

    1:如果alias名字与name相同,直接删除原有alias

    2:查看是否允许alias覆盖配置,如果不允许,进行校验,如果已经注册的alias的beanName跟当前注册的beanName不相同,则抛出alias名称已被注册到其他beanName上的异常

    3:检查是否有循环alias

    4:注册alias

    至此,默认标签的解析就梳理完了,后续我们进行自定义标签的解析。2019-07-01 17:32分 于图书馆

  • 相关阅读:
    Decimal、 Float、 Double 使用
    jdk1.7的collections.sort(List list)排序问题
    $watch、$digest、$apply
    BeanNameViewResolver
    This system is not registered with RHN
    JNI字段描述符-Java Native Interface Field Descriptors
    服务器端cs文件
    ASP.NET基础(一)
    Android开发日记(七)
    登陆 注册
  • 原文地址:https://www.cnblogs.com/aquariusm/p/11110509.html
Copyright © 2011-2022 走看看