Spring源码解析笔记2——默认标签的解析

继续前面的this.parseDefaultElement(ele, delegate)讨论。

//分别对4种不同的标签(import,alias,bean,beans)做了不同的处理。
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标签,import和alias和beans放在最后说明,继续this.processBeanDefinition(ele, delegate)方法。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //返回的bdHolder实例已经包含配置文件中的各种属性了,class,name等。
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            //对自定义标签进行解析。
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
            //注册解析的BeanDefinition
               BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name \'" + bdHolder.getBeanName() + "\'", ele, var5);
            }
            //通知监听器,这个bean已经加载完了
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
}
1.根据以上步骤分析,首先分析parseBeanDefinitionElement(Element ele):
  • parseBeanDefinitionElement(Element ele)方法:

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
         //提取元素中的id以及name。
        String id = ele.getAttribute("id");
        String nameAttr = ele.getAttribute("name");
        ArrayList aliases = new ArrayList();
        if(StringUtils.hasLength(nameAttr)) {
            String[] beanName = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(beanName));
        }
    
        String beanName1 = id;
        if(!StringUtils.hasText(id) && !aliases.isEmpty()) {
            beanName1 = (String)aliases.remove(0);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("No XML \'id\' specified - using \'" + beanName1 + "\' as bean name and " + aliases + " as aliases");
            }
        }
    
        if(containingBean == null) {
            this.checkNameUniqueness(beanName1, aliases, ele);
        }
    
        //核心方法,进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例。
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName1, containingBean);
        if(beanDefinition != null) {
            if(!StringUtils.hasText(beanName1)) {
                try {
                    if(containingBean != null) {
                        beanName1 = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    } else {
                        beanName1 = this.readerContext.generateBeanName(beanDefinition);
                        String aliasesArray = beanDefinition.getBeanClassName();
                        if(aliasesArray != null && beanName1.startsWith(aliasesArray) && beanName1.length() > aliasesArray.length() && !this.readerContext.getRegistry().isBeanNameInUse(aliasesArray)) {
                            aliases.add(aliasesArray);
                        }
                    }
    
                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Neither XML \'id\' nor \'name\' specified - using generated bean name [" + beanName1 + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }
    
            String[] aliasesArray1 = StringUtils.toStringArray(aliases);
            //将结果封装到BeanDefinitionHolder类中。
            return new BeanDefinitionHolder(beanDefinition, beanName1, aliasesArray1);
        } else {
            return null;
        }
    }
  • 上一步的核心方法:parseBeanDefinitionElement(ele, beanName1, containingBean),将其他所有属性统一封装至GenericBeanDefinition类型中。

    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 ex = null;
            //解析parent属性
            if(ele.hasAttribute("parent")) {
                ex = ele.getAttribute("parent");
            }
    
            //核心方法1,生成GenericBeanDefinition,要解析属性,就必须先要创建用于承载属性的实例。
            AbstractBeanDefinition bd = this.createBeanDefinition(className, ex);
    
            //硬编码解析默认的bean的各种属性。
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      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;
    }
    • this.createBeanDefinition(className, ex)是生成GenericBeanDefinition类型的实例。

      关于GenericBeanDefinition
      这里写图片描述
      BeanDefinition是配置文件bean>元素标签在容器中的内部表现形式。bean>元素标签拥有的class,scope,lazy-init等配置属性对应BeanDefinition中的beanClass,scope,lazyInit属性。

      在bean>标签中,父bean>用RootBeanDefinition表示,子bean>用ChildBeanDefinition表示,没有父bean>的bean>就使用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行了抽象。

      ChildBeanDefinition和RootBeanDefinition在spring2.5以后就被GenericBeanDefinition代替了,GenericBeanDefinition相比于RootBeanDefinition和ChildBeanDefinition在定义的时候就必须硬编码,GenericBeanDefinition的优点可以动态的为GenericBeanDefinition设置parent。

      //父bean的实例:
      <bean id="abstractServiceThread" class="com.project.schedual.ServiceThread" abstract="true">  
              <property name="baseDao" ref="baseDAO"></property>  
      </bean>  
      //子bean的实例
      <bean id="docReceiveFlowThread" parent="abstractServiceThread">  
              <property name="svc" ref="docReceiveFlowService"></property>  
      </bean>  
      .
      //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;
      }
    • 解析各种属性this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

      public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
          if(ele.hasAttribute("singleton")) {
              //scope与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) {
              //在嵌入beanDifinition的情况下没有单独指定scope属性则使用父类默认的属性。
              bd.setScope(containingBean.getScope());
          }
      
          if(ele.hasAttribute("abstract")) {
              bd.setAbstract("true".equals(ele.getAttribute("abstract")));
          }
      
          //解析lazy-init属性
          String lazyInit = ele.getAttribute("lazy-init");
          if("default".equals(lazyInit)) {
              lazyInit = this.defaults.getLazyInit();
          }
      
          //如果没有设置或者设置为其他字符都会被设置成false
          bd.setLazyInit("true".equals(lazyInit));
      
          //解析autowire属性
          String autowire = ele.getAttribute("autowire");
          bd.setAutowireMode(this.getAutowireMode(autowire));
      
          //解析dependency-check属性
          String dependencyCheck = ele.getAttribute("dependency-check");
          bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck));
          String autowireCandidate;
      
          //解析depends-on属性
          if(ele.hasAttribute("depends-on")) {
              autowireCandidate = ele.getAttribute("depends-on");
              bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
          }
      
          //解析autowire-candidate属性
          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));
              }
          }
      
          //解析primary属性
          if(ele.hasAttribute("primary")) {
              bd.setPrimary("true".equals(ele.getAttribute("primary")));
          }
      
          //解析init-method属性
          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);
          }
      
          //解析destroy-method属性
          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);
          }
      
          //解析factory-method属性
          if(ele.hasAttribute("factory-method")) {
              bd.setFactoryMethodName(ele.getAttribute("factory-method"));
          }
      
          //解析factory-bean属性
          if(ele.hasAttribute("factory-bean")) {
              bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
          }
      
          return bd;
      }
      
    • this.parseMetaElements(ele, bd); 解析子元素meta,元数据属性。

      //meta标签使用举例
      <bean id="myTestBean" class="bean.MyTestBean">
          <meta key="testStr" value="aaaaa">
      </bean> 
      
      
      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);
              }
          }
      }
    • this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());解析子元素lookup-method ,

      首先解释一下lookup-method这个子元素的作用,通常被称为获取器注入。

      // 定义一个水果类
      public class Fruit {
            public Fruit() {
                System.out.println("I got Fruit");
            }
      }
      
      // 苹果
      public class Apple extends Fruit {
          public Apple() {
             System.out.println("I got a fresh apple");
          }
      }
      
      // 香蕉
      public class Bananer extends Fruit {
            public Bananer () {
                 System.out.println("I got a  fresh bananer");
            }
      }
      
         //水果盘,可以拿到水果
         public abstract class FruitPlate{
         // 抽象方法获取新鲜水果
         protected abstract Fruit getFruit();
      }
      
      
      
      <bean id="fruitPlate1" class="cn.com.willchen.test.di.FruitPlate">
          <lookup-method name="getFruit" bean="apple"/>
      </bean>
      <bean id="fruitPlate2" class="cn.com.willchen.test.di.FruitPlate">
          <lookup-method name="getFruit" bean="bananer"/>
      </bean>
      
      
      public static void main(String[] args) {
         ApplicationContext app = new >ClassPathXmlApplicationContext("classpath:resource/applicationContext.xml");
      
         FruitPlate fp1= (FruitPlate)app.getBean("fruitPlate1");
         FruitPlate fp2 = (FruitPlate)app.getBean("fruitPlate2");
      
         fp1.getFruit();
         fp2.getFruit();
      }
      
    • this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());方法源码

      public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
          NodeList nl = beanEle.getChildNodes();
      
          for(int i = 0; i < nl.getLength(); ++i) {
              Node node = nl.item(i);
              //当且仅当Spring默认bean的子元素下且为<lookup-method时有效
              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);
              }
          }
      
      }
    • 解析子元素replaced-method

      解释replaced-method的作用

      public class TestChangMethod{
          public void changMe(){
          }
      }
      
      public class TestMethodReplacer implements MethodReplacer{
          @Override
          public Object reimplements(Object obj,Method method,Object[] args) throws Throwable{
              System.out.println("我替换了原有的方法");
              return null;
          }
      }
      //配置文件
      <bean id="testChangeMethod" class="com.demo3.TestChangeMethod">
          <replaced-method name="changeMe" replacer="replacer"/>
      </bean>
      <bean id="replacer" class="com.demo3.TestMethodReplacer"></bean>
      
      //测试
      public static void main(String[] args){
      
          ApplicationContext bf = new ClassPathXmlApplicationContext("springContext.xml");
          TestChangeMethod test = (TestChangeMethod )bf.getBean("testChangeMethod");
      }
    • this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());方法源码

       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(this.isCandidateElement(node) && this.nodeNameEquals(node, "replaced-method")) {
                  Element replacedMethodEle = (Element)node;
                  String name = replacedMethodEle.getAttribute("name");
                  String callback = replacedMethodEle.getAttribute("replacer");
                  ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
                  List argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type");
                  Iterator var11 = argTypeEles.iterator();
      
                  while(var11.hasNext()) {
                      Element argTypeEle = (Element)var11.next();
                      String match = argTypeEle.getAttribute("match");
                      match = StringUtils.hasText(match)?match:DomUtils.getTextValue(argTypeEle);
                      if(StringUtils.hasText(match)) {
                          replaceOverride.addTypeIdentifier(match);
                      }
                  }
      
                  replaceOverride.setSource(this.extractSource(replacedMethodEle));
                  overrides.addOverride(replaceOverride);
              }
          }
      
      }
    • 解析子元素constructor-arg

      ......
      <beans>
      <!-- 默认的情况是按照参数的顺序注入,当指定index索引后就可以改变注入参数的顺序 -->
          <bean id="helloBean" class="com.HelloBean">
              <constructor-arg index="0">
                  <value>张三</value>
              </constructor-arg>
              <constructor-arg index="1">
                  <value>李四</value>
              </constructor-arg>
          </bean>
      ......
      </beans>
      <!--上面的配置实现的功能就是对HelloBean自动寻找对应的构造函数,并在初始化的时候设置参数传进去-->
    • 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);
              if(this.isCandidateElement(node) && this.nodeNameEquals(node, "constructor-arg")) {
                  //解析constructor-arg
                  this.parseConstructorArgElement((Element)node, bd);
              }
          }
      
      }
      
      //this.parseConstructorArgElement((Element)node, bd);源码
      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 value = Integer.parseInt(indexAttr);
                  if(value < 0) {
                      this.error("\'index\' cannot be lower than 0", ele);
                  } else {
                      try {
                          this.parseState.push(new ConstructorArgumentEntry(value));
                          //解析constructor-arg
                          Object valueHolder = this.parsePropertyValue(ele, bd, (String)null);
                          //将type,name,index属性一并封装到valueHolder类型中。
                          ValueHolder valueHolder1 = new ValueHolder(valueHolder);
                          if(StringUtils.hasLength(typeAttr)) {
                              valueHolder1.setType(typeAttr);
                          }
      
                          if(StringUtils.hasLength(nameAttr)) {
                              valueHolder1.setName(nameAttr);
                          }
      
                          valueHolder1.setSource(this.extractSource(ele));
                          if(bd.getConstructorArgumentValues().hasIndexedArgumentValue(value)) {
                              this.error("Ambiguous constructor-arg entries for index " + value, ele);
                          } else {
                          //将valueHolder里面的type,name,index等,添加到BeanDefinition的ConstructorArgumentValues的IndexedArgumentValue属性中。       bd.getConstructorArgumentValues().addIndexedArgumentValue(value, valueHolder1);
                          }
                      } finally {
                          this.parseState.pop();
                      }
                  }
              } catch (NumberFormatException var19) {
                  this.error("Attribute \'index\' of tag \'constructor-arg\' must be an integer", ele);
              }
          } else {
              //如果没有index属性则自动寻找
              try {
                  this.parseState.push(new ConstructorArgumentEntry());
                  //解析constructor-arg
                  Object value1 = this.parsePropertyValue(ele, bd, (String)null);
                  ValueHolder valueHolder2 = new ValueHolder(value1);
                  if(StringUtils.hasLength(typeAttr)) {
                      valueHolder2.setType(typeAttr);
                  }
      
                  if(StringUtils.hasLength(nameAttr)) {
                      valueHolder2.setName(nameAttr);
                  }
      
                  valueHolder2.setSource(this.extractSource(ele));
                  //将valueHolder里面的type,name,index等,添加到BeanDefinition的ConstructorArgumentValues的genericArgumentValue属性中。                       bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder2);
              } finally {
                  this.parseState.pop();
              }
          }
      
      }
      
    • 关于 this.parseConstructorArgElements(ele, bd);的源码中的parsePropertyValue(Element ele, BeanDefinition bd, String propertyName)方法源码:

      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 hasRefAttribute = 0; hasRefAttribute < nl.getLength(); ++hasRefAttribute) {
              Node hasValueAttribute = nl.item(hasRefAttribute);
              //对应的description或者meta不处理。
              if(hasValueAttribute instanceof Element && !this.nodeNameEquals(hasValueAttribute, "description") && !this.nodeNameEquals(hasValueAttribute, "meta")) {
                  if(subElement != null) {
                      this.error(elementName + " must not contain more than one sub-element", ele);
                  } else {
                      subElement = (Element)hasValueAttribute;
                  }
              }
          }
      
          //解析constructor-arg的ref属性
          boolean var11 = ele.hasAttribute("ref");
          //解析constructor-arg的value属性
          boolean var12 = ele.hasAttribute("value");
          if(var11 && var12 || (var11 || var12) && subElement != null) {
              //如果同时有ref属性又有value属性,或者存在ref属性的同时有value属性且又有子元素,报错。
              this.error(elementName + " is only allowed to contain either \'ref\' attribute OR \'value\' attribute OR sub-element", ele);
          }
      
          if(var11) {
              String var13 = ele.getAttribute("ref");
              if(!StringUtils.hasText(var13)) {
                  this.error(elementName + " contains empty \'ref\' attribute", ele);
              }
              //使用RuntimeBeanReference封装对应的ref名称<constructor-arg ref="a">
              RuntimeBeanReference ref = new RuntimeBeanReference(var13);
              ref.setSource(this.extractSource(ele));
              return ref;
          } else if(var12) {
              //使用TypedStringValue封装对应的value名称<constructor-arg value="a">
              TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));
              valueHolder.setSource(this.extractSource(ele));
              return valueHolder;
          } else if(subElement != null) {
              //子元素的处理
              /**
              <constructor-arg>
                  <map>
                      <entry key="key" value="value">
                  </map>
              </constructor-arg>
              **/
              return this.parsePropertySubElement(subElement, bd);
          } else {
              //没有ref也没有value也没有子元素,spring报错。
              this.error(elementName + " must specify a ref or value", ele);
              return null;
          }
      }
    • 子元素的处理 this.parsePropertySubElement(subElement, bd)源码根据源码可以看到constructor-arg支持的子元素

      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 nullHolder2 = this.parseBeanDefinitionElement(ele, bd);
              if(nullHolder2 != null) {
                  nullHolder2 = this.decorateBeanDefinitionIfRequired(ele, nullHolder2, bd);
              }
      
              return nullHolder2;
          } else if(this.nodeNameEquals(ele, "ref")) {
              String nullHolder1 = ele.getAttribute("bean");
              boolean toParent = false;
              if(!StringUtils.hasLength(nullHolder1)) {
                  nullHolder1 = ele.getAttribute("local");
                  if(!StringUtils.hasLength(nullHolder1)) {
                      nullHolder1 = ele.getAttribute("parent");
                      toParent = true;
                      if(!StringUtils.hasLength(nullHolder1)) {
                          this.error("\'bean\', \'local\' or \'parent\' is required for <ref> element", ele);
                          return null;
                      }
                  }
              }
      
              if(!StringUtils.hasText(nullHolder1)) {
                  this.error("<ref> element contains empty target attribute", ele);
                  return null;
              } else {
                  RuntimeBeanReference ref = new RuntimeBeanReference(nullHolder1, 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;
          }
      }
    • 解析子元素property,property的作用如下。

      <bean id="test" class="test.TestClass">
          <property name="testStr" value="aaa" />
      </bean>
      或者
      <bean id="a">
          <property name="p">
              <list>
                  <value>aa</value>
                  <value>bb</value>
              </list>
          </property>
      </bean>
    • 解析property的方法this.parsePropertyElements(ele, bd)源码为:

      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);
              }
          }
      
      }
      
      //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进行封装,并记录在了BeanDefinition中的PropertyValues属性中。
                      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();
              }
      
          }
      }
      
    • 解析子元素qualifier,该元素的作用是,大多数时候都用注解的方式。解析的过程与前面相似。

      public interface EmployeeService {
          public EmployeeDto getEmployeeById(Long id);
      }
      //上述接口的实现类
      @Service("service")
      public class EmployeeServiceImpl implements EmployeeService {
          public EmployeeDto getEmployeeById(Long id) {
              return new EmployeeDto();
          }
      }
      //上述接口的第二个实现类
      @Service("service1")
      public class EmployeeServiceImpl1 implements EmployeeService {
          public EmployeeDto getEmployeeById(Long id) {
              return new EmployeeDto();
          }
      }
      //控制层的调用代码如下:
      @Controller
      @RequestMapping("/emplayee.do")
      public class EmployeeInfoControl {
          @Autowired
          EmployeeService employeeService;
      
      }
      /**
      此时启动tomcat会报错,因为该接口有两个实现类,spring不知道该去绑定哪一个,此时需要使用qualifier注解;问题解决。
      **/
      @Controller
      @RequestMapping("/emplayee.do")
      public class EmployeeInfoControl {
      
          @Autowired
          @Qualifier("service")
          EmployeeService employeeService;
      }
    • Qualifier的配置文件使用方法。

      <bean id="myTestBean" class="bean.MyTestBean">
      <qualifier type="org.Springframework.beans.factory.annotation.Qualifier" value="qf" />
      </bean>


2.根据文章开头processBeanDefinition方法下面的bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)的decorateBeanDefinitionIfRequired方法:该方法是用来解析默认标签中的自定义标签。
<!--解释一下此处的自定义标签,spring中以bean形式出现的标签分为默认和自定义,
    而默认的bean中也有一些自定义标签,例如bean的属性。-->
<!--实例:默认的bean标签自定义属性标签-->
<bean id="test" class="test.MyClass">
      <mybean:user username="aaa">
</bean>
//追踪decorateBeanDefinitionIfRequired方法
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
        return this.decorateBeanDefinitionIfRequired(ele, definitionHolder, (BeanDefinition)null);
    }
/**
   可以看到decorateBeanDefinitionIfRequired的第三个参数是null,这里需要传>的是父类的beanDefinition,其实是为了使用父类的scope属性,以备子类没有设>置scope时默认使用父类的属性,此处是顶层配置,所以传递null。
**/

//继续跟踪decorateBeanDefinitionIfRequired
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, >BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
       BeanDefinitionHolder finalDefinition = definitionHolder;
       NamedNodeMap attributes = ele.getAttributes();

       //遍历所有属性,看看是否有适用于修饰的属性
       for(int children = 0; children < attributes.getLength(); ++children) {
           Node i = attributes.item(children);
           finalDefinition = this.decorateIfRequired(i, finalDefinition, >containingBd);
       }

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

       return finalDefinition;
   }


 //继续跟踪decorateIfRequired方法
 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;
    }
3.根据文章开头processBeanDefinition方法下面的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry())追踪:
public static void registerBeanDefinition(BeanDefinitionHolder >definitionHolder, BeanDefinitionRegistry registry) throws >BeanDefinitionStoreException {
       String beanName = definitionHolder.getBeanName();
       //使用beanName做唯一标识。此处可以看出解析的beanDefinition都会被注册在BeanDefinitionRegistry类型的registry中。
       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的注册,其实就是将beanDefinition直接放入map中,使用beanName作为key。除此之外,spring还利用registerBeanDefinition做了一些其他的事。
 **/    

//继续追踪registerBeanDefinition方法:
 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 {
         /**
             注册前的最后一次校验,此处的校验不同于之前的XML文件校验
             主要是对于AbstractBeanDefinition属性中的methodOverrides校验
             校验methodOverrides是否与工厂方法并存或者methodOverrides对应方法根本不存在。
         **/
               ((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);
        if(oldBeanDefinition != null) {
            //如果对应的BeanName已经注册且在配置中配置了bean不允许被覆盖,则抛异常。
            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()) {
                Map var4 = this.beanDefinitionMap;
                //beanDefinitionMap是全局变量,存在并发的情况。
                synchronized(this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    ArrayList updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                   updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                   if(this.manualSingletonNames.contains(beanName)) {
                        LinkedHashSet updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            } else {
               //注册beanDefinition
               this.beanDefinitionMap.put(beanName, beanDefinition);

               //记录对应的beanName
               this.beanDefinitionNames.add(beanName);
               this.manualSingletonNames.remove(beanName);
           }

          this.frozenBeanDefinitionNames = null;
       }

       if(oldBeanDefinition != null || this.containsSingleton(beanName)) {
           //重置所有beanName对应的缓存。
           this.resetBeanDefinition(beanName);
       }

  }

   //继续追踪前一步的registerAlias方法,注册别名的方法:
   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 {
           String registeredName = (String)this.aliasMap.get(alias);
           if(registeredName != null) {
               if(registeredName.equals(name)) {
                   return;
               }
               //如果alias不允许覆盖则抛出异常。
               if(!this.allowAliasOverriding()) {
                   throw new IllegalStateException("Cannot register alias \'" + >alias + "\' for name \'" + name + "\': It is already registered for name \'" + >registeredName + "\'.");
               }
           }
           //循环检查,A——>B存在时,如果再次出现A——>C——>B时则会抛出异常。
           this.checkForAliasCircle(name, alias);
           this.aliasMap.put(alias, name);
       }

   }


4.最开始只解析了bean标签,此处补充alias和import和beans标签。
  • alias标签的解析。
    首先解释一下alias的作用,在对bean进行定义时,除了使用id属性来指定名称以外,为了提供多个名称,可以使用alias标签来指定。

    <!--例如-->
    <bean id="testBean" class="com.test">
    
    <!--给这个JavaBean添加别名的第一种方式-->
    <bean id="testBean" name="testBean,testBean2" class="com.test"/>
    
    <!--给这个JavaBean添加别名的第二种方式-->
    <bean id="testBean" class="com.test"/>
    <alias name="testBean" alias="testBean,testBean2"/>
    
    <!--第二个例子:组件A在XML配置文件中定义了一个名为componentA的DataSource类型的bean,但是组件B却想在其XML文件中以componentB命名来引用此bean。而且在主程序MyApp的XML配置文件中,希望以myApp的名字来引用此bean。最后容器加载3个XML来生成最终的ApplicationContext。-->
    <alias name="componentA" alias="componentB"/>
    <alias name="componentA" alias="myApp"/>
    • 查看this.processAliasRegistration(ele)源码
      protected void processAliasRegistration(Element ele) {
          //读取beanName
          String name = ele.getAttribute("name");
          //获取alias
          String alias = ele.getAttribute("alias");
          boolean valid = true;
          if(!StringUtils.hasText(name)) {
              this.getReaderContext().error("Name must not be empty", ele);
              valid = false;
          }
      
          if(!StringUtils.hasText(alias)) {
              this.getReaderContext().error("Alias must not be empty", ele);
              valid = false;
          }
      
          if(valid) {
              try {
                  this.getReaderContext().getRegistry().registerAlias(name, alias);
              } catch (Exception var6) {
                  this.getReaderContext().error("Failed to register alias \'" + alias + "\' for bean with name \'" + name + "\'", ele, var6);
              }
      
              //别名注册以后通知监听器做相应处理。
              this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele));
          }
      
      }
  • impot标签的解析
    首先解释一下import标签的作用,将配置文件分块,利用import导入多个配置文件。

    <?xml version="1.0" encoding="gb2312"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    
    <import resource="CTIContext.xml" />
    <import resource="customerContext.xml" />
    <import resource="customerServingContext.xml" />
    <import resource="manageContext.xml" />
    <import resource="routineContext.xml" />
    <import resource="systemContext.xml" />
    ...........
    </beans>
    • this.importBeanDefinitionResource(ele)的源码:
      protected void importBeanDefinitionResource(Element ele) {
          //获取resource属性。
          String location = ele.getAttribute("resource");
      
          //如果不存在resource属性则不做任何处理。
          if(!StringUtils.hasText(location)) {
              this.getReaderContext().error("Resource location must not be empty", ele);
          } else {
      
              //解析系统属性,格式如:"${user.dir}"
              location = this.getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
      
              //判定location是URI是绝对的还是相对的。
              boolean absoluteLocation = false;
      
              try {
                  absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
              } catch (URISyntaxException var11) {
                  ;
              }
      
              int actResArray;
              //如果是绝对URI则直接根据地址加载对应的配置文件。
              if(absoluteLocation) {
                  try {
                      actResArray = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
                      if(this.logger.isDebugEnabled()) {
                          this.logger.debug("Imported " + actResArray + " bean definitions from URL location [" + location + "]");
                      }
                  } catch (BeanDefinitionStoreException var10) {
                      this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10);
                  }
              } else {
                  //如果是相对地址则根据相对地址计算出绝对地址。
                  try {
                      Resource relativeResource = this.getReaderContext().getResource().createRelative(location);
                      if(relativeResource.exists()) {
                          actResArray = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                          actualResources.add(relativeResource);
                      } else {
                          //如果解析不成功,则使用默认的解析器
                          String baseLocation = this.getReaderContext().getResource().getURL().toString();
                          actResArray = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);
                      }
      
                      if(this.logger.isDebugEnabled()) {
                          this.logger.debug("Imported " + actResArray + " bean definitions from relative location [" + location + "]");
                      }
                  } catch (IOException var8) {
                      this.getReaderContext().error("Failed to resolve current resource location", ele, var8);
                  } catch (BeanDefinitionStoreException var9) {
                      this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9);
                  }
              }
              //解析后进行监听器激活处理。
              Resource[] actResArray1 = (Resource[])actualResources.toArray(new Resource[actualResources.size()]);
              this.getReaderContext().fireImportProcessed(location, actResArray1, this.extractSource(ele));
          }
      }
  • 嵌入式beans标签的解析
    xbeans标签与单独的配置文件并没有太大差别,是递归调用bean的解析过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值