• spring原理之四种基本标签的解析


    • 四种标签

    在spring的配置文件中存在四种基本的标签分别是:beans,bean,import,alias

    四种标签的功能:

    beans:定义一个单独的应用配置(测试配置,开发配置等),在服务器部署的时候可以选择部署哪一个应用配置

    bean:最基本的定义一个对象

    import:导入配置文件

    alias:为定义的bean取别名

    • 解析的入口

    spring先用sax解析器完成对xml配置文件的解析,将xml中的标签在内存中创造成一颗文档树。

    protected void doRegisterBeanDefinitions(Element root) {
            
            BeanDefinitionParserDelegate parent = this.delegate; 
            this.delegate = createDelegate(getReaderContext(), root, parent);
    
            if (this.delegate.isDefaultNamespace(root)) {  //文档以<beans>标签作为根标签则进行以下的判断
                String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);//获取beans标签下的profile属性 判断profile属性
                if (StringUtils.hasText(profileSpec)) {
                    String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                            profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);//将profile属性的值按照分隔符分隔成字符串数组if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { //当所给定的profile属性的值全部都没激活则不用继续加载接下来的xml
                        if (logger.isInfoEnabled()) {
                            logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                    "] not matching: " + getReaderContext().getResource());
                        }
                        return;
                    }
                }
            }
    
            preProcessXml(root); //用户如果重写这个方法表示在加载bean,inport,beans,alias等标签前应该执行的操作
            parseBeanDefinitions(root, this.delegate); //加载bean,inport,beans,alias等标签
            postProcessXml(root);//用户如果重写这个方法表示在加载bean,inport,beans,alias等标签后应该执行的操作
    
            this.delegate = parent;
        }

    上述操作主要是对<beans profiles=""><beans/>标签进行操作,在xml文件中可能存在多个beans标签,每一个beans标签中可以定义一个项目的配置profiles可以为这个配置命名,spring框架会根据profiles的激活情况加载对应的配置。

     激活profiles的几种方法 :
     作为SpringMVC中的DispatcherServlet的初始化参数
     作为Web 应用上下文中的初始化参数
     作为JNDI的入口
     作为环境变量 (Windows为服务器时windows中添加环境变量)
     作为虚拟机的系统参数(linux为服务器时,在~/.bash_profile里最后一行增加 export SPRING_PROFILES_ACTIVE=dev)
     使用@AtivceProfile来进行激活

    • bean标签的解析1-beanname的解析

    下面解析根标签

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
            String id = ele.getAttribute(ID_ATTRIBUTE);  
            String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    
            List<String> aliases = new ArrayList<String>();
            if (StringUtils.hasLength(nameAttr)) {
                String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                aliases.addAll(Arrays.asList(nameArr));
            }  //将多个name存储到aliases
    
            String beanName = id;
            if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
                beanName = aliases.remove(0);
                if (logger.isDebugEnabled()) {
                    logger.debug("No XML 'id' specified - using '" + beanName +
                            "' as bean name and " + aliases + " as aliases");
                }
            } // 如果bean标签没有id属性则将第一个name的值赋给bean name否则beanname的值为id
    
            if (containingBean == null) {
                checkNameUniqueness(beanName, aliases, ele); //判断bean name有没有被加载过
            }
    
            AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); //解析<bean>里面的标签
            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); //依据类名生成一个独一无二的名字 如 classname#0
                            
                            String beanClassName = beanDefinition.getBeanClassName(); //真正的类名
                            if (beanClassName != null &&
                                    beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                    !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                                aliases.add(beanClassName);
                            } //如果真正的类名之前没有被注册到aliases或者register则注册进去
                        }
                        if (logger.isDebugEnabled()) {
                            logger.debug("Neither XML 'id' nor 'name' specified - " +
                                    "using generated bean name [" + beanName + "]");
                        }
                    }
                    catch (Exception ex) {
                        error(ex.getMessage(), ele);
                        return null;
                    }
                }
                String[] aliasesArray = StringUtils.toStringArray(aliases);
                return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
            }
    
            return null;
        }

    上面的代码主要是获取beanname

    1.有id属性取id为beanname

    2有那么属性取第一个name属性为beanname

    3有外部bean(即当前被创造的bean只是另外一个bean的属性)如果有parent取parentbean的beanname加上$child加上系统自动生成的hashcode,如果没有parent但是有factorybeanname取factorybeanname加上$create加系统自动生成的hashcode

    4.无外部bean,再判断是否有parentbean如果有按照已生成的数量命名如parentbeanname$child#0,parentbeanname$child#1........;如果没有parentbean但是有factorybeanname按照已生成的数量命名factorybeanname$create#0,factorybeanname$create#1......

    • bean标签的解析2-attribute的解析

      

    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
                BeanDefinition containingBean, AbstractBeanDefinition bd) {
    
            if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
                error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
            }
            else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
                bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
            }
            else if (containingBean != null) {
                // Take default from containing bean in case of an inner bean definition.
                bd.setScope(containingBean.getScope());
            }
    
            if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
                bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
            }
    
            String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
            if (DEFAULT_VALUE.equals(lazyInit)) {
                lazyInit = this.defaults.getLazyInit();
            }
            bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
    
            String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
            bd.setAutowireMode(getAutowireMode(autowire));
    
            String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
            bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
    
            if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
                String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
                bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
            }
    
            String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
            if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
                String candidatePattern = this.defaults.getAutowireCandidates();
                if (candidatePattern != null) {
                    String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
                    bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
                }
            }
            else {
                bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
            }
    
            if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
                bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
            }
    
            if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
                String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
                if (!"".equals(initMethodName)) {
                    bd.setInitMethodName(initMethodName);
                }
            }
            else {
                if (this.defaults.getInitMethod() != null) {
                    bd.setInitMethodName(this.defaults.getInitMethod());
                    bd.setEnforceInitMethod(false);
                }
            }
    
            if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
                String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
                bd.setDestroyMethodName(destroyMethodName);
            }
            else {
                if (this.defaults.getDestroyMethod() != null) {
                    bd.setDestroyMethodName(this.defaults.getDestroyMethod());
                    bd.setEnforceDestroyMethod(false);
                }
            }
    
            if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
                bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
            }
            if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
                bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
            }
    
            return bd;
        }

    上述代码包含了对<bean> 标签中属性值得解析,属性值包括:scope,singleton,abstract,lazy-init,autowire,dependcy-check,depends-on,autowire-candidate,primary,init-method,destroy-method,factory-method,factory-bean

    接下来是对<bean>标签内的元素标签解析。具体的解析步骤类似:将相应类型的节点的元素值取出放到beandefinition中

           parseMetaElements(ele, bd);//解析<meta key='' value=''> 元数据标签, 将键值对放入attributeAccessor
                parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //动态代理生成类
                parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    
                parseConstructorArgElements(ele, bd);  //解析<constructor-arg  index=''  type='' name=''/> 属性
                parsePropertyElements(ele, bd); //解析<property   name=''/> 属性
                parseQualifierElements(ele, bd); //解析<qualifier type='' value=''><attribute key='' vaule='' /><qualifier>
    • 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 (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
                    Element metaElement = (Element) node;
                    String key = metaElement.getAttribute(KEY_ATTRIBUTE);
                    String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
                    BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
                    attribute.setSource(extractSource(metaElement));
                    attributeAccessor.addMetadataAttribute(attribute);
                }
            }
        }

    将meta标签的key和value属性放到beandefinition

    • 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 (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
                    Element ele = (Element) node;
                    String methodName = ele.getAttribute(NAME_ATTRIBUTE);
                    String beanRef = ele.getAttribute(BEAN_ELEMENT);
                    LookupOverride override = new LookupOverride(methodName, beanRef);
                    override.setSource(extractSource(ele));
                    overrides.addOverride(override);
                }
            }
        }
    
    

    将lookup-mathod标签的name和bean属性放到beandefinition

    • replace-method的解析
    public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
            NodeList nl = beanEle.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
                    Element replacedMethodEle = (Element) node;
                    String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
                    String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
                    ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
                    // Look for arg-type match elements.
                    List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
                    for (Element argTypeEle : argTypeEles) {
                        String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
                        match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
                        if (StringUtils.hasText(match)) {
                            replaceOverride.addTypeIdentifier(match);
                        }
                    }
                    replaceOverride.setSource(extractSource(replacedMethodEle));
                    overrides.addOverride(replaceOverride);
                }
            }
        }

     将replace-mathod标签的name和bean属性放到beandefinition

    • 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 (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
                    parseConstructorArgElement((Element) node, bd);
                }
            }
        }
    public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
            String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
            String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
            String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
            if (StringUtils.hasLength(indexAttr)) {
                try {
                    int index = Integer.parseInt(indexAttr);
                    if (index < 0) {
                        error("'index' cannot be lower than 0", ele);
                    }
                    else {
                        try {
                            this.parseState.push(new ConstructorArgumentEntry(index));
                            Object value = parsePropertyValue(ele, bd, null);
                            ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                            if (StringUtils.hasLength(typeAttr)) {
                                valueHolder.setType(typeAttr);
                            }
                            if (StringUtils.hasLength(nameAttr)) {
                                valueHolder.setName(nameAttr);
                            }
                            valueHolder.setSource(extractSource(ele));
                            if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                                error("Ambiguous constructor-arg entries for index " + index, ele);
                            }
                            else {
                                bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
                            }
                        }
                        finally {
                            this.parseState.pop();
                        }
                    }
                }
                catch (NumberFormatException ex) {
                    error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
                }
            }
            else {
                try {
                    this.parseState.push(new ConstructorArgumentEntry());
                    Object value = parsePropertyValue(ele, bd, null);
                    ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
                    if (StringUtils.hasLength(typeAttr)) {
                        valueHolder.setType(typeAttr);
                    }
                    if (StringUtils.hasLength(nameAttr)) {
                        valueHolder.setName(nameAttr);
                    }
                    valueHolder.setSource(extractSource(ele));
                    bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
                }
                finally {
                    this.parseState.pop();
                }
            }
        }

      

    上述代码将constructor标签中的子标签和属性值进行解析

    •  解析property标签

    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 (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
                    parseQualifierElement((Element) node, bd);
                }
            }
        }
    public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
            String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
            if (!StringUtils.hasLength(typeName)) {
                error("Tag 'qualifier' must have a 'type' attribute", ele);
                return;
            }
            this.parseState.push(new QualifierEntry(typeName));
            try {
                AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
                qualifier.setSource(extractSource(ele));
                String value = ele.getAttribute(VALUE_ATTRIBUTE);
                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 (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
                        Element attributeEle = (Element) node;
                        String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
                        String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
                        if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
                            BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
                            attribute.setSource(extractSource(attributeEle));
                            qualifier.addMetadataAttribute(attribute);
                        }
                        else {
                            error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
                            return;
                        }
                    }
                }
                bd.addQualifier(qualifier);
            }
            finally {
                this.parseState.pop();
            }
        }

    上述代码遍历property标签完成对标签元素的提取。

    • 解析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 (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
                    parseQualifierElement((Element) node, bd);
                }
            }
        }
    public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
            String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
            if (!StringUtils.hasLength(typeName)) {
                error("Tag 'qualifier' must have a 'type' attribute", ele);
                return;
            }
            this.parseState.push(new QualifierEntry(typeName));
            try {
                AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
                qualifier.setSource(extractSource(ele));
                String value = ele.getAttribute(VALUE_ATTRIBUTE);
                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 (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
                        Element attributeEle = (Element) node;
                        String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
                        String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
                        if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
                            BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
                            attribute.setSource(extractSource(attributeEle));
                            qualifier.addMetadataAttribute(attribute);
                        }
                        else {
                            error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
                            return;
                        }
                    }
                }
                bd.addQualifier(qualifier);
            }
            finally {
                this.parseState.pop();
            }
        }

    上述代码完成对qualifier元素的提取

  • 相关阅读:
    zmap zgrab 环境搭建
    RF是如何工作的?
    RF的优缺点
    国内NLP的那些人那些会
    B-、B+、B*树
    关于LDA的gibbs采样,为什么可以获得正确的样本?
    LDA算法里面Dirichlet分布的两个参数alpha和beta怎样确定?
    如何确定LDA的主题个数
    SMO算法精解
    奇异值与主成分分析(PCA)
  • 原文地址:https://www.cnblogs.com/ll9507/p/11298221.html
Copyright © 2020-2023  润新知