默认标签的解析
Posted lkeji388
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了默认标签的解析相关的知识,希望对你有一定的参考价值。
默认标签的解析是在parseDefaultElement方法中进行的,方法中的功能一目了然 ,分别对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标签的解析及注册
bean标签的计息最为复杂也最为重要,如果能理解此标签的解析过程,其他标签解析自然会迎刃而解。首先先看processBeanDefinition()方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException var5) { this.getReaderContext().error("Failed to register bean definition with name ‘" + bdHolder.getBeanName() + "‘", ele, var5); } this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
大致的逻辑:
1、首先用BeanDefinitionParserDelegate的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类的实例bdHolder,经过这个方法,bdHolder实例已经包含我们配置文件中配置的各种属性了,例如class,name,id alias之类的属性。
2、当返回的bdHolder不为空的情况下若存在默认标签的子节点下在用自定义属性,还需要再次对自定义标签进行解析。
3、解析完成后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法。
4、最后发出响应时间,通知相关的监听器,这个bean已经加载完成了。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return this.parseBeanDefinitionElement(ele, (BeanDefinition)null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute("id");//解析ID属性 String nameAttr = ele.getAttribute("name");//解析name属性 List<String> aliases = new ArrayList();
//分割name属性 if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; "); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(id) && !aliases.isEmpty()) { beanName = (String)aliases.remove(0); if (this.logger.isDebugEnabled()) { this.logger.debug("No XML ‘id‘ specified - using ‘" + beanName + "‘ as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { this.checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try {
//如果不存在beanNames那么根据Spring中提供的命名规则为当前bean生成对应的beanName 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 (this.logger.isDebugEnabled()) { this.logger.debug("Neither XML ‘id‘ nor ‘name‘ specified - using generated bean name [" + beanName + "]"); } } catch (Exception var9) { this.error(var9.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } else { return null; } }
对spring的解析犹如剥洋葱,一层一层的进行,尽管现在只能看到对属性ID以及name的解析,Srping在外层又做了一个当前层的功能架构,在当前层完成的主要工作:
1、提取元素中的Id及name属性
2、进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例中
3、如果检测到bean没有指定beanName,那么使用默认规则为Bean生成的beanName
4、如果获取到的信息封装到BeanDefinitionHolder的实例中
查看步骤(2)中对标签其他属性的解析过程
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 parent = null;
//解析parent属性 if (ele.hasAttribute("parent")) { parent = ele.getAttribute("parent"); } //创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
//硬编码解析默认bean的各种属性 this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//提取Decription bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
//解析元数据 this.parseMetaElements(ele, bd);
//解析lookup-method属性 this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
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; }
创建用于属性记载的BeanDefintion
BeanDefinition是一个接口,在spring中存在三种实现 GenericBeanDefinition,ChildBeanDefinition ,RootBeanDefinition,三种实现均继承了AbstractBeanDefinition
其中BeanDefinition是配置文件<bean>元素标签在容器中的内部表示形式。<bean>元素标签拥有class、scope、lazy-init等配置属性BeanDefinition则提供了相应的beanClass,
scope,lazyInit属性,BeanDefinition和<bean>中的属性一一对应。其中RootBeanDefintion是最常用的实现类,它对应一般性的<bean>元素标签。
在配置文件中可以定义父<bean>和子<bean>,父<bean>用RootBeanDefintion表示,而子<bean>用ChildBeanDefintion表示,而没有父<bean>的<bean>就用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象。
Spring通过BeanDefintion将配置文件中的<bean>配置信息转换为容器的内部表示,并将这些BeanDefintion注册到BeanDefintionRegistry中。Spring容器的BeanDefintionRegistry就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接用BeanDefintionRegistry中读取配置信息。
以上是关于默认标签的解析的主要内容,如果未能解决你的问题,请参考以下文章