概述
parseDefaultElement
processBeanDefinition (bean标签的解析即注册)
解析BeanDefinition
parseDefaultElement Spring中有两种解析Bean 的方式。如果根节点或者子节点采用默认命名空间的话,则调用 parseDefaultElement()
进行默认标签解析,否则调用 delegate.parseCustomElement()
方法进行自定义解析。下面就这两个方法进行详细分析说明,先从默认标签解析过程开始,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private void parseDefaultElement (Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { doRegisterBeanDefinitions(ele); } }
方法的功能一目了然,分别是对四种不同的标签进行解析,分别是 import、alias、bean、beans。咱门从常用的标签bean 开始,如果能理解此标签的解析过程,其他的标签的解析自然会迎刃而解。
processBeanDefinition (bean标签的解析即注册) 如果遇到标签为bean,则调用processBeanDefinition()
方法进行bean标签解析,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 protected void processBeanDefinition (Element ele,BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to register bean definition with name '" + bdHolder.getBeanName() + "'" , ele, ex); } getReaderContext().fireComponentRegistered( new BeanComponentDefinition (bdHolder)); } }
整个过程分为四个步骤
调用 BeanDefinitionParserDelegate.parseBeanDefinitionElement()
进行元素解析,解析过程中如果失败,返回 null,错误由 ProblemReporter
处理。如果解析成功则返回BeanDefinitionHolder实例 bdHolder。BeanDefinitionHolder是对BeanDefinition简单装饰,里面持有bean name 和alias的 BeanDefinition。
若实例bdHolder不为空,则调用 BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()
进行自定义标签处理
解析完成后,则调用BeanDefinitionReaderUtils.registerBeanDefinition()
对bdHolder进行注册
发出响应事件,通知相关的监听器,完成 Bean 标签解析
解析BeanDefinition 下面我们就针对各个操作做具体分析。首先我们从元素解析即信息提取开始,也就是BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
进入BeanDefinitionDelegate类的parseBeanDefinitionElement方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 @Nullable public BeanDefinitionHolder parseBeanDefinitionElement (Element ele, @Nullable BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); 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.isTraceEnabled()) { logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases" ); } } if (containingBean == null ) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null ) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null ) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this .readerContext.getRegistry(), true ); } else { beanName = this .readerContext.generateBeanName(beanDefinition); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this .readerContext.getRegistry().isBeanNameInUse(beanClassName) ) { aliases.add(beanClassName); } } if (logger.isTraceEnabled()) { logger.trace("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]" ); } } catch (Exception ex) { error(ex.getMessage(), ele); return null ; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder (beanDefinition, beanName, aliasesArray); } return null ; }
这个方法还没有对Bean标签进行解析,只是在解析动作之前做了一些功能架构,主要的工作有:
解析 id、name 属性,确定 alias 集合,检测 beanName 是否唯一
调用方法 parseBeanDefinitionElement()
对属性进行解析并封装成 GenericBeanDefinition实例 beanDefinition
如果检测到bean没有指定beanName,那么使用默认规则为此Bean生成beanName
根据所获取的信息(beanName、aliases、beanDefinition)构造 BeanDefinitionHolder 实例对象并返回。
这里有必要说下 beanName 的命名规则:
如果 id 不为空,则 beanName = id。
如果 id 为空,但是 alias 不空,则 beanName 为 alias 的第一个元素。
如果两者都为空,则根据默认规则来设置 beanName。
上面三个步骤第二个步骤为核心方法,它主要承担解析 Bean 标签中所有的属性值。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public AbstractBeanDefinition parseBeanDefinitionElement ( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this .parseState.push(new BeanEntry (beanName)); String className = null ; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null ; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this .readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { 。。。。省略异常 } finally { this .parseState.pop(); } return null ; }
到这里,Bean标签的所有属性我们都可以看到其解析的过程,也就说到这里我们已经解析一个基本可用的 BeanDefinition。
由于篇幅有点长,在下面文章中将对此进行仔细分析。