Spring Bean 标签解析

打印 上一主题 下一主题

主题 525|帖子 525|积分 1575

上一篇文章讲到了标签在 parseDefaultElement 方法中进行解析,本篇文章将讲解这部分内容

bean 标签解析

查看 processBeanDefinition 方法,针对各个操作作具体分析:
  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  2.     // 1.解析 BeanDefinition
  3.     BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  4.     if (bdHolder != null) {
  5.         bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
  6.         try {
  7.             BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
  8.         } catch (BeanDefinitionStoreException var5) {
  9.             this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
  10.         }
  11.         this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
  12.     }
  13. }
复制代码
1. 解析 BeanDefinition

首先从元素解析及信息提取开始,进入 parseBeanDefinitionElement 方法
  1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
  2.     return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
  3. }
  4. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
  5.     // 1.1 解析id属性
  6.     String id = ele.getAttribute("id");
  7.     // 1.2 解析name属性
  8.     String nameAttr = ele.getAttribute("name");
  9.     List<String> aliases = new ArrayList();
  10.     if (StringUtils.hasLength(nameAttr)) {
  11.         String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
  12.         aliases.addAll(Arrays.asList(nameArr));
  13.     }
  14.     String beanName = id;
  15.     if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
  16.         beanName = (String)aliases.remove(0);
  17.         if (this.logger.isTraceEnabled()) {
  18.             this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
  19.         }
  20.     }
  21.     if (containingBean == null) {
  22.         this.checkNameUniqueness(beanName, aliases, ele);
  23.     }
  24.         // 2. 解析其他属性
  25.     AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
  26.     if (beanDefinition != null) {
  27.         if (!StringUtils.hasText(beanName)) {
  28.             try {
  29.                 // 3. 如果不存在beanName就根据Spring提供的命名规则为当前bean生成对应的beanName
  30.                 if (containingBean != null) {
  31.                     beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
  32.                 } else {
  33.                     beanName = this.readerContext.generateBeanName(beanDefinition);
  34.                     String beanClassName = beanDefinition.getBeanClassName();
  35.                     if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
  36.                         aliases.add(beanClassName);
  37.                     }
  38.                 }
  39.                 if (this.logger.isTraceEnabled()) {
  40.                     this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
  41.                 }
  42.             } catch (Exception var9) {
  43.                 this.error(var9.getMessage(), ele);
  44.                 return null;
  45.             }
  46.         }
  47.         String[] aliasesArray = StringUtils.toStringArray(aliases);
  48.         // 4. 封装到 BeanDefinitionHolder 的实例
  49.         return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
  50.     } else {
  51.         return null;
  52.     }
  53. }
复制代码
该方法完成的主要工作包括以下内容:

  • 提取元素中的 id 以及 name 属性
  • 进一步解析其他属性并统一封装至 GenericBeanDefinition 类型的实例中
  • 如果检测到 bean 没有指定 beanName,那么使用默认规则为此 Bean 生成 beanName
  • 将获取到的信息封装到 BeanDefinitionHolder 的实例中
进一步查看步骤二对标签的其他属性的解析过程:
  1. public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
  2.     this.parseState.push(new BeanEntry(beanName));
  3.     String className = null;
  4.     // 解析class属性
  5.     if (ele.hasAttribute("class")) {
  6.         className = ele.getAttribute("class").trim();
  7.     }
  8.         // 解析parent属性
  9.     String parent = null;
  10.     if (ele.hasAttribute("parent")) {
  11.         parent = ele.getAttribute("parent");
  12.     }
  13.     try {
  14.         // 创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition实例
  15.         AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
  16.         // 硬编码解析默认bean的各种属性
  17.         this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
  18.         // 提取description
  19.         bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
  20.         // 解析元数据
  21.         this.parseMetaElements(ele, bd);
  22.         // 解析lookup-method属性
  23.         this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
  24.         // 解析replaced-method属性
  25.         this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
  26.         // 解析构造函数参数
  27.         this.parseConstructorArgElements(ele, bd);
  28.         // 解析property子元素
  29.         this.parsePropertyElements(ele, bd);
  30.         // 解析qualifier子元素
  31.         this.parseQualifierElements(ele, bd);
  32.         bd.setResource(this.readerContext.getResource());
  33.         bd.setSource(this.extractSource(ele));
  34.         AbstractBeanDefinition var7 = bd;
  35.         return var7;
  36.     } catch (ClassNotFoundException var13) {
  37.         this.error("Bean class [" + className + "] not found", ele, var13);
  38.     } catch (NoClassDefFoundError var14) {
  39.         this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
  40.     } catch (Throwable var15) {
  41.         this.error("Unexpected failure during bean definition parsing", ele, var15);
  42.     } finally {
  43.         this.parseState.pop();
  44.     }
  45.     return null;
  46. }
复制代码
接下来,我们继续一些复杂标签属性的解析:
1.1 创建用于属性承载的 BeanDefinition

BeanDefinition 是一个接口,在 Spring 中存在三种实现:RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition,三种实现类均继承了 AbstractBeanDefinition
BeanDefinition 是配置文件  元素标签在容器中的内部表示形式, 标签拥有 class、scope、lazy-init 等配置属性,BeanDefinition 就提供了对应的 beanClass、scope、lazyInit 属性
由此可见,要解析属性首先要创建用于承载属性的实例,也就是创建 GenericBeanDefinition 类型的实例,createBeanDefinition 方法的作用就是实现此功能
  1. public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
  2.     GenericBeanDefinition bd = new GenericBeanDefinition();
  3.     bd.setParentName(parentName);
  4.     if (className != null) {
  5.         // 如果classLoader不为空,则使用传入的classLoader加载对象
  6.         // 否则就只是记录className
  7.         if (classLoader != null) {
  8.             bd.setBeanClass(ClassUtils.forName(className, classLoader));
  9.         } else {
  10.             bd.setBeanClassName(className);
  11.         }
  12.     }
  13.     return bd;
  14. }
复制代码
2. 解析各种属性

当我们创建了 bean 信息的承载实例后,便可以进行 bean 信息的各种属性解析了,parseBeanDefinitionAttributes 方法是对 element 所有元素属性进行解析:
  1. public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
  2.     // 解析scope属性
  3.     if (ele.hasAttribute("singleton")) {
  4.         this.error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
  5.     } else if (ele.hasAttribute("scope")) {
  6.         bd.setScope(ele.getAttribute("scope"));
  7.     } else if (containingBean != null) {
  8.         bd.setScope(containingBean.getScope());
  9.     }
  10.         // 解析singleton属性
  11.     if (ele.hasAttribute("abstract")) {
  12.         bd.setAbstract("true".equals(ele.getAttribute("abstract")));
  13.     }
  14.         // 解析lazy-init属性
  15.     String lazyInit = ele.getAttribute("lazy-init");
  16.     if (this.isDefaultValue(lazyInit)) {
  17.         lazyInit = this.defaults.getLazyInit();
  18.     }
  19.         // 若没有设置或设置成其他字符都会被设置为false
  20.     bd.setLazyInit("true".equals(lazyInit));
  21.     String autowire = ele.getAttribute("autowire");
  22.     bd.setAutowireMode(this.getAutowireMode(autowire));
  23.     String autowireCandidate;
  24.     if (ele.hasAttribute("depends-on")) {
  25.         autowireCandidate = ele.getAttribute("depends-on");
  26.         bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
  27.     }
  28.         // 解析autowire属性
  29.     autowireCandidate = ele.getAttribute("autowire-candidate");
  30.     String destroyMethodName;
  31.     if (this.isDefaultValue(autowireCandidate)) {
  32.         destroyMethodName = this.defaults.getAutowireCandidates();
  33.         if (destroyMethodName != null) {
  34.             String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
  35.             bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
  36.         }
  37.     } else {
  38.         bd.setAutowireCandidate("true".equals(autowireCandidate));
  39.     }
  40.         // 解析primary属性
  41.     if (ele.hasAttribute("primary")) {
  42.         bd.setPrimary("true".equals(ele.getAttribute("primary")));
  43.     }
  44.         // 解析init-method属性
  45.     if (ele.hasAttribute("init-method")) {
  46.         destroyMethodName = ele.getAttribute("init-method");
  47.         bd.setInitMethodName(destroyMethodName);
  48.     } else if (this.defaults.getInitMethod() != null) {
  49.         bd.setInitMethodName(this.defaults.getInitMethod());
  50.         bd.setEnforceInitMethod(false);
  51.     }
  52.         // 解析destroy-method属性
  53.     if (ele.hasAttribute("destroy-method")) {
  54.         destroyMethodName = ele.getAttribute("destroy-method");
  55.         bd.setDestroyMethodName(destroyMethodName);
  56.     } else if (this.defaults.getDestroyMethod() != null) {
  57.         bd.setDestroyMethodName(this.defaults.getDestroyMethod());
  58.         bd.setEnforceDestroyMethod(false);
  59.     }
  60.         // 解析factory-method属性
  61.     if (ele.hasAttribute("factory-method")) {
  62.         bd.setFactoryMethodName(ele.getAttribute("factory-method"));
  63.     }
  64.         // 解析factory-bean属性
  65.     if (ele.hasAttribute("factory-bean")) {
  66.         bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
  67.     }
  68.     return bd;
  69. }
复制代码
注册解析的 BeanDefinition

得到 BeanDefinition 后,剩下的工作就是注册了,也就是 processBeanDefinition 方法中的
registerBeanDefinition 方法
  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  2.     BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  3.     if (bdHolder != null) {
  4.         bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
  5.         try {
  6.             // 注册解析的 BeanDefinition
  7.             BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
  8.         } catch (BeanDefinitionStoreException var5) {
  9.             this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
  10.         }
  11.         this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
  12.     }
  13. }
  14. public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
  15.     // 使用beanName做唯一标识注册
  16.     String beanName = definitionHolder.getBeanName();
  17.     registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
  18.     // 注册所有的别名
  19.     String[] aliases = definitionHolder.getAliases();
  20.     if (aliases != null) {
  21.         String[] var4 = aliases;
  22.         int var5 = aliases.length;
  23.         for(int var6 = 0; var6 < var5; ++var6) {
  24.             String alias = var4[var6];
  25.             registry.registerAlias(beanName, alias);
  26.         }
  27.     }
  28. }
复制代码
解析的 beanDefinition 都会被注册到 BeanDefinitionRegistry 类型的实例 registry 中,而对于 beanDefinition 的注册分成两个部分:通过 beanName 注册以及通过别名注册
1. 通过 beanName 注册
  1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
  2.     Assert.hasText(beanName, "Bean name must not be empty");
  3.     Assert.notNull(beanDefinition, "BeanDefinition must not be null");
  4.     if (beanDefinition instanceof AbstractBeanDefinition) {
  5.         try {
  6.             // 注册前的最后一次校验
  7.             ((AbstractBeanDefinition)beanDefinition).validate();
  8.         } catch (BeanDefinitionValidationException var8) {
  9.             throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
  10.         }
  11.     }
  12.     // 处理beanName已经注册的情况
  13.     BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
  14.     if (existingDefinition != null) {
  15.         // 如果对应BeanName已经注册且在配置中配置了bean不允许被覆盖,则抛出异常
  16.         if (!this.isAllowBeanDefinitionOverriding()) {
  17.             throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
  18.         }
  19.         if (existingDefinition.getRole() < beanDefinition.getRole()) {
  20.             if (this.logger.isInfoEnabled()) {
  21.                 this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
  22.             }
  23.         } else if (!beanDefinition.equals(existingDefinition)) {
  24.             if (this.logger.isDebugEnabled()) {
  25.                 this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
  26.             }
  27.         } else if (this.logger.isTraceEnabled()) {
  28.             this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
  29.         }
  30.         this.beanDefinitionMap.put(beanName, beanDefinition);
  31.     } else {
  32.         // 检查工厂是否处于bean创建阶段
  33.         if (this.hasBeanCreationStarted()) {
  34.             // 因为beanDefinitionMap是全局变量,会存在并发访问的情况
  35.             synchronized(this.beanDefinitionMap) {
  36.                 this.beanDefinitionMap.put(beanName, beanDefinition);
  37.                 List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
  38.                 updatedDefinitions.addAll(this.beanDefinitionNames);
  39.                 updatedDefinitions.add(beanName);
  40.                 this.beanDefinitionNames = updatedDefinitions;
  41.                 this.removeManualSingletonName(beanName);
  42.             }
  43.         } else {
  44.             // 注册beanDefinition
  45.             this.beanDefinitionMap.put(beanName, beanDefinition);
  46.             // 记录beanName
  47.             this.beanDefinitionNames.add(beanName);
  48.             this.removeManualSingletonName(beanName);
  49.         }
  50.         this.frozenBeanDefinitionNames = null;
  51.     }
  52.     if (existingDefinition == null && !this.containsSingleton(beanName)) {
  53.         if (this.isConfigurationFrozen()) {
  54.             this.clearByTypeCache();
  55.         }
  56.     } else {
  57.         this.resetBeanDefinition(beanName);
  58.     }
  59. }
复制代码
在对于 bean 的注册处理方式上,主要进行了几个步骤:

  • 对 AbstractBeanDefinition 校验
  • 加入 map 缓存
  • 清楚解析之前留下的对应的 beanName 的缓存
2. 通过别名注册 BeanDefinition
  1. public void registerAlias(String name, String alias) {
  2.     Assert.hasText(name, "'name' must not be empty");
  3.     Assert.hasText(alias, "'alias' must not be empty");
  4.     synchronized(this.aliasMap) {
  5.         // 如果beanName和alias相同的话不记录alias,并删除对应的alias
  6.         if (alias.equals(name)) {
  7.             this.aliasMap.remove(alias);
  8.             if (this.logger.isDebugEnabled()) {
  9.                 this.logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
  10.             }
  11.         } else {
  12.             String registeredName = (String)this.aliasMap.get(alias);
  13.             if (registeredName != null) {
  14.                 if (registeredName.equals(name)) {
  15.                     return;
  16.                 }
  17.                 if (!this.allowAliasOverriding()) {
  18.                     throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
  19.                 }
  20.                 if (this.logger.isDebugEnabled()) {
  21.                     this.logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'");
  22.                 }
  23.             }
  24.                         // 检查是否存在循环指向,如A->B,A->C->B
  25.             this.checkForAliasCircle(name, alias);
  26.             this.aliasMap.put(alias, name);
  27.             if (this.logger.isTraceEnabled()) {
  28.                 this.logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
  29.             }
  30.         }
  31.     }
  32. }
复制代码
注册 alias 的步骤如下:

  • alias 与 beanName 相同情况处理
  • alias 循环检查
  • 注册 alias


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户国营

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表