默认标签的解析

上一篇分析了整体的 xml 文件解析,形成 BeanDefinition 并注册到 IOC 容器中,但并没有详细的说明具体的解析,这一篇主要说一下 默认标签的解析,下一篇主要说自定义标签的解析。

parseDefaultElement

解析默认的元素标签

  1. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
  2. if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
  3. importBeanDefinitionResource(ele);
  4. }
  5. else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
  6. // 处理别名,会将 beanName 和别名一块注册到 SimpleAliasRegistry 中的 aliasMap 中去。
  7. processAliasRegistration(ele);
  8. }
  9. else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
  10. // 解析 bean 标签
  11. processBeanDefinition(ele, delegate);
  12. }
  13. else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
  14. // recurse,会产生递归解析
  15. doRegisterBeanDefinitions(ele);
  16. }
  17. }

importBeanDefinitionResource

主要解析 标签中 resource 标签,此处会产生递归调用,importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);

  1. 获取 resource 属性所表示的路径
  2. 解析系统属性
  3. 针对绝对路径和相对路径进行不同的解析
  4. 相对路径的情况下,需要计算出绝对路径的地址
  5. 调用 loadBeanDefinitions 进行递归解析
  6. 通知监听器,完成解析
  1. protected void importBeanDefinitionResource(Element ele) {
  2. // 获取resource属性
  3. String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
  4. if (!StringUtils.hasText(location)) {
  5. // 如果不存在resource属性则不作任何处理
  6. getReaderContext().error("Resource location must not be empty", ele);
  7. return;
  8. }
  9. // Resolve system properties: e.g. "${user.dir}"
  10. // 解析系统属性
  11. location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
  12. Set<Resource> actualResources = new LinkedHashSet<>(4);
  13. // Discover whether the location is an absolute or relative URI
  14. // 判断location是绝对URI还是相对URI
  15. boolean absoluteLocation = false;
  16. try {
  17. absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
  18. }
  19. catch (URISyntaxException ex) {
  20. // cannot convert to an URI, considering the location relative
  21. // unless it is the well-known Spring prefix "classpath*:"
  22. }
  23. // Absolute or relative?
  24. // 如果是绝对URI则直接根据地质加载对应的配置文件
  25. if (absoluteLocation) {
  26. try {
  27. int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
  28. if (logger.isTraceEnabled()) {
  29. logger.trace("Imported " + importCount + " bean definitions from URL location [" + location + "]");
  30. }
  31. }
  32. catch (BeanDefinitionStoreException ex) {
  33. getReaderContext().error(
  34. "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
  35. }
  36. }
  37. else {
  38. // No URL -> considering resource location as relative to the current file.
  39. // 如果是相对路径,则根据相对地址计算出绝对地址
  40. try {
  41. int importCount;
  42. // Resource存在多个子类实现类,如VfsResource、FileSystemResource等,而每个resource的createRekative方式实现都不一样,
  43. // 所以这里先使用子类的方法尝试解析
  44. Resource relativeResource = getReaderContext().getResource().createRelative(location);
  45. if (relativeResource.exists()) {
  46. importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
  47. actualResources.add(relativeResource);
  48. }
  49. else {
  50. // 如果解析不成功,则使用默认的解析器ResourcePatternResolver进行解析
  51. String baseLocation = getReaderContext().getResource().getURL().toString();
  52. importCount = getReaderContext().getReader().loadBeanDefinitions(
  53. StringUtils.applyRelativePath(baseLocation, location), actualResources);
  54. }
  55. if (logger.isTraceEnabled()) {
  56. logger.trace("Imported " + importCount + " bean definitions from relative location [" + location + "]");
  57. }
  58. }
  59. catch (IOException ex) {
  60. getReaderContext().error("Failed to resolve current resource location", ele, ex);
  61. }
  62. catch (BeanDefinitionStoreException ex) {
  63. getReaderContext().error(
  64. "Failed to import bean definitions from relative location [" + location + "]", ele, ex);
  65. }
  66. }
  67. // 解析后进行监听器激活处理
  68. Resource[] actResArray = actualResources.toArray(new Resource[0]);
  69. getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
  70. }

processAliasRegistration

主要是将 beanName 和别名一块注册到 SimpleAliasRegistry 中的 aliasMap 中去

processBeanDefinition

  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  2. // beanDefinitionHolder是beanDefinition对象的封装类,封装了BeanDefinition,bean的名字和别名,用它来完成向IOC容器的注册
  3. // 得到这个beanDefinitionHolder就意味着beandefinition是通过BeanDefinitionParserDelegate对xml元素的信息按照spring的bean规则进行解析得到的
  4. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  5. if (bdHolder != null) {
  6. bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
  7. try {
  8. // Register the final decorated instance.
  9. // 向ioc容器注册解析得到的beandefinition的地方
  10. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
  11. }
  12. catch (BeanDefinitionStoreException ex) {
  13. getReaderContext().error("Failed to register bean definition with name '" +
  14. bdHolder.getBeanName() + "'", ele, ex);
  15. }
  16. // Send registration event.
  17. // 在beandefinition向ioc容器注册完成之后,发送消息
  18. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
  19. }
  20. }

delegate.parseBeanDefinitionElement(ele)

主要完成的有以下工作:

  1. 解析bean标签中的id和name属性
  2. 解析其他属性,封装到 GenericBeanDefinition 中
  3. 如果没有指定 beanName,将会按照默认的规则生成对应的 beanName
  4. 将解析到的 GenericBeanDefinition 中去。
  1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
  2. // 解析id属性
  3. String id = ele.getAttribute(ID_ATTRIBUTE);
  4. // 解析name属性
  5. String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
  6. // 如果bean有别名的话,那么将别名分割解析
  7. List<String> aliases = new ArrayList<>();
  8. if (StringUtils.hasLength(nameAttr)) {
  9. String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
  10. aliases.addAll(Arrays.asList(nameArr));
  11. }
  12. String beanName = id;
  13. if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
  14. beanName = aliases.remove(0);
  15. if (logger.isTraceEnabled()) {
  16. logger.trace("No XML 'id' specified - using '" + beanName +
  17. "' as bean name and " + aliases + " as aliases");
  18. }
  19. }
  20. if (containingBean == null) {
  21. checkNameUniqueness(beanName, aliases, ele);
  22. }
  23. // 对bean元素的详细解析
  24. AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
  25. if (beanDefinition != null) {
  26. if (!StringUtils.hasText(beanName)) {
  27. try {
  28. // 如果不存在beanname,那么根据spring中提供的命名规则为当前bean生成对应的beanName
  29. if (containingBean != null) {
  30. beanName = BeanDefinitionReaderUtils.generateBeanName(
  31. beanDefinition, this.readerContext.getRegistry(), true);
  32. }
  33. else {
  34. beanName = this.readerContext.generateBeanName(beanDefinition);
  35. // Register an alias for the plain bean class name, if still possible,
  36. // if the generator returned the class name plus a suffix.
  37. // This is expected for Spring 1.2/2.0 backwards compatibility.
  38. String beanClassName = beanDefinition.getBeanClassName();
  39. if (beanClassName != null &&
  40. beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
  41. !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
  42. aliases.add(beanClassName);
  43. }
  44. }
  45. if (logger.isTraceEnabled()) {
  46. logger.trace("Neither XML 'id' nor 'name' specified - " +
  47. "using generated bean name [" + beanName + "]");
  48. }
  49. }
  50. catch (Exception ex) {
  51. error(ex.getMessage(), ele);
  52. return null;
  53. }
  54. }
  55. String[] aliasesArray = StringUtils.toStringArray(aliases);
  56. return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
  57. }
  58. return null;
  59. }

parseBeanDefinitionElement

  1. public AbstractBeanDefinition parseBeanDefinitionElement(
  2. Element ele, String beanName, @Nullable BeanDefinition containingBean) {
  3. this.parseState.push(new BeanEntry(beanName));
  4. // 解析class属性
  5. String className = null;
  6. if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
  7. className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
  8. }
  9. // 解析parent属性
  10. String parent = null;
  11. if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
  12. parent = ele.getAttribute(PARENT_ATTRIBUTE);
  13. }
  14. try {
  15. // 创建装在bean信息的AbstractBeanDefinition对象,实际的实现是GenericBeanDefinition
  16. AbstractBeanDefinition bd = createBeanDefinition(className, parent);
  17. // 解析bean标签的各种其他属性
  18. parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
  19. // 设置description信息
  20. bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
  21. // 解析元数据
  22. parseMetaElements(ele, bd);
  23. // 解析lookup-method属性
  24. parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
  25. // 解析replaced-method属性
  26. parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
  27. // 解析构造函数参数
  28. parseConstructorArgElements(ele, bd);
  29. // 解析property子元素
  30. parsePropertyElements(ele, bd);
  31. // 解析qualifier子元素
  32. parseQualifierElements(ele, bd);
  33. bd.setResource(this.readerContext.getResource());
  34. bd.setSource(extractSource(ele));
  35. return bd;
  36. }
  37. catch (ClassNotFoundException ex) {
  38. error("Bean class [" + className + "] not found", ele, ex);
  39. }
  40. catch (NoClassDefFoundError err) {
  41. error("Class that bean class [" + className + "] depends on not found", ele, err);
  42. }
  43. catch (Throwable ex) {
  44. error("Unexpected failure during bean definition parsing", ele, ex);
  45. }
  46. finally {
  47. this.parseState.pop();
  48. }
  49. return null;
  50. }

createBeanDefinition()

通过 Utils 创建了 GenericBeanDefinition

  1. BeanDefinitionReaderUtils.createBeanDefinition(
  2. parentName, className, this.readerContext.getBeanClassLoader());
  3. public static AbstractBeanDefinition createBeanDefinition(
  4. @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
  5. GenericBeanDefinition bd = new GenericBeanDefinition();
  6. bd.setParentName(parentName);
  7. if (className != null) {
  8. if (classLoader != null) {
  9. bd.setBeanClass(ClassUtils.forName(className, classLoader));
  10. }
  11. else {
  12. bd.setBeanClassName(className);
  13. }
  14. }
  15. return bd;
  16. }

parseBeanDefinitionAttributes

  1. public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
  2. @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
  3. // 解析singleton属性
  4. if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
  5. error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
  6. }
  7. else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
  8. bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
  9. }
  10. else if (containingBean != null) {
  11. // Take default from containing bean in case of an inner bean definition.
  12. // 在嵌入beanDefinitiono情况下且没有单独指定scope属性则使用父类默认的属性
  13. bd.setScope(containingBean.getScope());
  14. }
  15. // 解析abstract属性
  16. if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
  17. bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
  18. }
  19. // 解析lazy-init属性
  20. String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
  21. if (isDefaultValue(lazyInit)) {
  22. lazyInit = this.defaults.getLazyInit();
  23. }
  24. // 如果没有设置或者设置成其他字符都会被设置为false
  25. bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
  26. // 解析autowire属性
  27. String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
  28. bd.setAutowireMode(getAutowireMode(autowire));
  29. // 解析depends-on属性
  30. if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
  31. String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
  32. bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
  33. }
  34. // 解析autowire-candidate属性
  35. String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
  36. if (isDefaultValue(autowireCandidate)) {
  37. String candidatePattern = this.defaults.getAutowireCandidates();
  38. if (candidatePattern != null) {
  39. String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
  40. bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
  41. }
  42. }
  43. else {
  44. bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
  45. }
  46. // 解析primary属性
  47. if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
  48. bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
  49. }
  50. // 解析init-method属性
  51. if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
  52. String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
  53. bd.setInitMethodName(initMethodName);
  54. }
  55. else if (this.defaults.getInitMethod() != null) {
  56. bd.setInitMethodName(this.defaults.getInitMethod());
  57. bd.setEnforceInitMethod(false);
  58. }
  59. // 解析destory-method属性
  60. if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
  61. String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
  62. bd.setDestroyMethodName(destroyMethodName);
  63. }
  64. else if (this.defaults.getDestroyMethod() != null) {
  65. bd.setDestroyMethodName(this.defaults.getDestroyMethod());
  66. bd.setEnforceDestroyMethod(false);
  67. }
  68. // 解析factory-method属性
  69. if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
  70. bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
  71. }
  72. // 解析factory-bean属性
  73. if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
  74. bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
  75. }
  76. return bd;
  77. }

parseMetaElements

  1. public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
  2. // 获取当前节点的所有子元素
  3. NodeList nl = ele.getChildNodes();
  4. for (int i = 0; i < nl.getLength(); i++) {
  5. Node node = nl.item(i);
  6. // 提取meta
  7. if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
  8. Element metaElement = (Element) node;
  9. String key = metaElement.getAttribute(KEY_ATTRIBUTE);
  10. String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
  11. // 使用key、value构造beanMetadataAttribute
  12. BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
  13. attribute.setSource(extractSource(metaElement));
  14. // 记录信息
  15. attributeAccessor.addMetadataAttribute(attribute);
  16. }
  17. }
  18. }

parseLookupOverrideSubElements

lookup-method:动态地将一个原型 bean 作为 bean 对象注入到单例 bean 中。

  1. public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
  2. NodeList nl = beanEle.getChildNodes();
  3. for (int i = 0; i < nl.getLength(); i++) {
  4. Node node = nl.item(i);
  5. // 仅当在spring默认bean的子元素下且为<lookup-method>时有效
  6. if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
  7. Element ele = (Element) node;
  8. // 获取要修饰的方法
  9. String methodName = ele.getAttribute(NAME_ATTRIBUTE);
  10. // 获取配置返回的bean
  11. String beanRef = ele.getAttribute(BEAN_ELEMENT);
  12. LookupOverride override = new LookupOverride(methodName, beanRef);
  13. override.setSource(extractSource(ele));
  14. overrides.addOverride(override);
  15. }
  16. }
  17. }

parseReplacedMethodSubElements

replaced-method:用于方法的动态替换

  1. public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
  2. NodeList nl = beanEle.getChildNodes();
  3. for (int i = 0; i < nl.getLength(); i++) {
  4. Node node = nl.item(i);
  5. // 仅当在spring默认的bean的子元素下且为<replaced-method>时有效
  6. if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
  7. Element replacedMethodEle = (Element) node;
  8. // 提取要替换的旧方法
  9. String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
  10. // 提取对应的新的替换方法
  11. String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
  12. ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
  13. // Look for arg-type match elements.
  14. List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
  15. for (Element argTypeEle : argTypeEles) {
  16. // 记录参数
  17. String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
  18. match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
  19. if (StringUtils.hasText(match)) {
  20. replaceOverride.addTypeIdentifier(match);
  21. }
  22. }
  23. replaceOverride.setSource(extractSource(replacedMethodEle));
  24. overrides.addOverride(replaceOverride);
  25. }
  26. }
  27. }

parseConstructorArgElements

  1. public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
  2. // 获取index属性
  3. String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
  4. // 获取type属性
  5. String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
  6. // 提取name属性
  7. String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
  8. if (StringUtils.hasLength(indexAttr)) {
  9. try {
  10. int index = Integer.parseInt(indexAttr);
  11. if (index < 0) {
  12. error("'index' cannot be lower than 0", ele);
  13. }
  14. else {
  15. try {
  16. this.parseState.push(new ConstructorArgumentEntry(index));
  17. // 解析ele对应的属性元素
  18. Object value = parsePropertyValue(ele, bd, null);
  19. ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
  20. if (StringUtils.hasLength(typeAttr)) {
  21. valueHolder.setType(typeAttr);
  22. }
  23. if (StringUtils.hasLength(nameAttr)) {
  24. valueHolder.setName(nameAttr);
  25. }
  26. valueHolder.setSource(extractSource(ele));
  27. // 不允许重复指定相同参数
  28. if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
  29. error("Ambiguous constructor-arg entries for index " + index, ele);
  30. }
  31. else {
  32. bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
  33. }
  34. }
  35. finally {
  36. this.parseState.pop();
  37. }
  38. }
  39. }
  40. catch (NumberFormatException ex) {
  41. error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
  42. }
  43. }
  44. else {
  45. // 没有index属性则忽略属性,自动寻找
  46. try {
  47. this.parseState.push(new ConstructorArgumentEntry());
  48. Object value = parsePropertyValue(ele, bd, null);
  49. ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
  50. if (StringUtils.hasLength(typeAttr)) {
  51. valueHolder.setType(typeAttr);
  52. }
  53. if (StringUtils.hasLength(nameAttr)) {
  54. valueHolder.setName(nameAttr);
  55. }
  56. valueHolder.setSource(extractSource(ele));
  57. bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
  58. }
  59. finally {
  60. this.parseState.pop();
  61. }
  62. }
  63. }

parsePropertyElements

  1. public void parsePropertyElement(Element ele, BeanDefinition bd) {
  2. // 获取配置元素中name的值
  3. String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
  4. if (!StringUtils.hasLength(propertyName)) {
  5. error("Tag 'property' must have a 'name' attribute", ele);
  6. return;
  7. }
  8. this.parseState.push(new PropertyEntry(propertyName));
  9. try {
  10. // 不允许多次对同一属性配置,如果已经存在同名的property属性,那么就不进行解析
  11. if (bd.getPropertyValues().contains(propertyName)) {
  12. error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
  13. return;
  14. }
  15. // 此处用来解析property值,返回的对象对应对bean定义的property属性设置的解析结果,这个解析结果会封装到PropertyValue对象中,然后
  16. // 设置到BeanDefinitionHolder中去
  17. Object val = parsePropertyValue(ele, bd, propertyName);
  18. PropertyValue pv = new PropertyValue(propertyName, val);
  19. parseMetaElements(ele, pv);
  20. pv.setSource(extractSource(ele));
  21. bd.getPropertyValues().addPropertyValue(pv);
  22. }
  23. finally {
  24. this.parseState.pop();
  25. }
  26. }

parseQualifierElements

  1. public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
  2. String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
  3. if (!StringUtils.hasLength(typeName)) {
  4. error("Tag 'qualifier' must have a 'type' attribute", ele);
  5. return;
  6. }
  7. this.parseState.push(new QualifierEntry(typeName));
  8. try {
  9. AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
  10. qualifier.setSource(extractSource(ele));
  11. String value = ele.getAttribute(VALUE_ATTRIBUTE);
  12. if (StringUtils.hasLength(value)) {
  13. qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
  14. }
  15. NodeList nl = ele.getChildNodes();
  16. for (int i = 0; i < nl.getLength(); i++) {
  17. Node node = nl.item(i);
  18. if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
  19. Element attributeEle = (Element) node;
  20. String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
  21. String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
  22. if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
  23. BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
  24. attribute.setSource(extractSource(attributeEle));
  25. qualifier.addMetadataAttribute(attribute);
  26. }
  27. else {
  28. error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
  29. return;
  30. }
  31. }
  32. }
  33. bd.addQualifier(qualifier);
  34. }
  35. finally {
  36. this.parseState.pop();
  37. }
  38. }

03-Spring默认标签解析的更多相关文章

  1. spring源码深度解析— IOC 之 默认标签解析(上)

    概述 接前两篇文章  spring源码深度解析—Spring的整体架构和环境搭建  和  spring源码深度解析— IOC 之 容器的基本实现 本文主要研究Spring标签的解析,Spring的标签 ...

  2. spring源码深度解析— IOC 之 默认标签解析(下)

    在spring源码深度解析— IOC 之 默认标签解析(上)中我们已经完成了从xml配置文件到BeanDefinition的转换,转换后的实例是GenericBeanDefinition的实例.本文主 ...

  3. 【Spring源码深度解析学习系列】默认标签解析(三)

    Spring的标签包括默认标签和自定义标签两种 默认标签的解析方法: ###DefaultBeanDefinitionDocumentReader.java### private void parse ...

  4. Spring IoC 默认标签解析

    前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 容 ...

  5. Spring自定义标签解析与实现

           在Spring Bean注册解析(一)和Spring Bean注册解析(二)中我们讲到,Spring在解析xml文件中的标签的时候会区分当前的标签是四种基本标签(import.alias ...

  6. Spring Bean 标签解析

    上一篇文章讲到了标签在 parseDefaultElement 方法中进行解析,本篇文章将讲解这部分内容 bean 标签解析 查看 processBeanDefinition 方法,针对各个操作作具体 ...

  7. Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签

    写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...

  8. Spring 系列教程之默认标签的解析

    Spring 系列教程之默认标签的解析 之前提到过 Spring 中的标签包括默认标签和自定义标签两种,而两种标签的用法以及解析方式存在着很大的不同,本章节重点带领读者详细分析默认标签的解析过程. 默 ...

  9. spring源码学习之默认标签的解析(一)

    继续spring源码的学习之路,现在越来越觉得这个真的很枯燥的,而且我觉得要是自己来看源码,真的看不下去,不是没有耐心,而是真的没有头绪,我觉得结合着书来看,还是很有必要的,最起码大致的流程是能够捋清 ...

随机推荐

  1. 二进制安装kubernetes(四) kube-scheduler组件安装

    介绍资料转载地址:https://www.jianshu.com/p/c4c60ccda8d0 kube-scheduler在集群中的作用 kube-scheduler是以插件形式存在的组件,正因为以 ...

  2. spring再学习之AOP准备

    一.aop思想: 横向重复,纵向抽取 1.乱码 2.事务管理 3,action 二.spring能够为容器中管理的对象生成代理对象 1.spring能帮我们生成代理对象 2.spring实现aop的原 ...

  3. codeforces 758D

    D. Ability To Convert time limit per test 1 second memory limit per test 256 megabytes input standar ...

  4. C# 类 (1)

    通常每个类都会单独定义在自己的文件里,方便区分 Class 里面定义了 变量 属性 方法 实例化这个Class,得到一个对象,然后可以使用这个对象的变量 属性和方法 属性 Properties 像是一 ...

  5. 【php代码审计】熊海cms1.0

    0x01 环境安装 1. 熊海cms1.0 (http://js.down.chinaz.com/201503/xhcms_v1.0.rar) 2.seay代码审计工具 3. phpstudy (ph ...

  6. JVM 报 GC Overhead limit exceeded 是什么意思?

    默认情况下,并不是等堆内存耗尽,才会报 OutOfMemoryError,而是如果 JVM 觉得 GC 效率不高,也会报这个错误. 那么怎么评价 GC 效率不高呢?来看下源码: 呢?来看下源码gcOv ...

  7. node.js 中间件

    node.js 中间件 node.js middleware Express middleware body-parser cookie-parser cookie-session cors csur ...

  8. JavaScript Array methods performance compare

    JavaScript Array methods performance compare JavaScript数组方法的性能对比 env $ node -v # v12.18.0 push vs un ...

  9. flex layout & demos

    flex layout & demos https://codepen.io/xgqfrms/pen/jjLPKN https://css-tricks.com/snippets/css/a- ...

  10. ES-Next classes static properties

    ES-Next classes static properties https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ...