内容简介:原文出自:import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程。在方法
原文出自: http://cmsblogs.com
import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程。
在方法 parseDefaultElement()
中,如果遇到标签 为 bean 则调用 processBeanDefinition()
方法进行 bean 标签解析,如下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
整个过程分为四个步骤
-
调用
BeanDefinitionParserDelegate.parseBeanDefinitionElement()
进行元素解析,解析过程中如果失败,返回 null,错误由ProblemReporter
处理。如果解析成功则返回 BeanDefinitionHolder 实例 bdHolder。BeanDefinitionHolder 为持有 name 和 alias 的 BeanDefinition。 -
若实例 bdHolder 不为空,则调用
BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()
进行自定义标签处理 -
解析完成后,则调用
BeanDefinitionReaderUtils.registerBeanDefinition()
对 bdHolder 进行注册 - 发出响应事件,通知相关的监听器,完成 Bean 标签解析
先看方法 parseBeanDefinitionElement()
,如下:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { // 解析 ID 属性 String id = ele.getAttribute(ID_ATTRIBUTE); // 解析 name 属性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); // 分割 name 属性 List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } 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"); } } // 检查 name 的唯一性 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // 解析 属性,构造 AbstractBeanDefinition AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { // 如果 beanName 不存在,则根据条件构造一个 beanName if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (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); // 封装 BeanDefinitionHolder return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
这个方法还没有对 Bean 标签进行解析,只是在解析动作之前做了一些功能架构,主要的工作有:
parseBeanDefinitionElement()
这里有必要说下 beanName 的命名规则:如果 id 不为空,则 beanName = id;如果 id 为空,但是 alias 不空,则 beanName 为 alias 的第一个元素,如果两者都为空,则根据默认规则来设置 beanName。
上面三个步骤第二个步骤为核心方法,它主要承担解析 Bean 标签中所有的属性值。如下:
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; // 解析 class 属性 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null; // 解析 parent 属性 if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { // 创建用于承载属性的 GenericBeanDefinition 实例 AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 解析默认 bean 的各种属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 提取 description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // 解析元数据 parseMetaElements(ele, bd); // 解析 lookup-method 属性 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // 解析 replaced-method 属性 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 解析构造函数参数 parseConstructorArgElements(ele, bd); // 解析 property 子元素 parsePropertyElements(ele, bd); // 解析 qualifier 子元素 parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
到这里,Bean 标签的所有属性我们都可以看到其解析的过程,也就说到这里我们已经解析一个基本可用的 BeanDefinition。
由于解析过程较为漫长,篇幅较大,为了更好的观看体验,将这篇博文进行拆分。下篇博客主要介绍 BeanDefinition,以及解析默认 Bean 的过程( parseBeanDefinitionAttributes()
)
--
以上所述就是小编给大家介绍的《【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- spring5 源码深度解析— IOC 之 开启 bean 的加载
- Unreal性能测评 | GPU检测、重要参数解析,开启高效优化的新姿势!
- MySQL开启远程连接
- 如何开启Nginx缓存
- [译] 开启性能预算
- 开启前台Service
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。