Spring--解析默认标签
2018-02-09 17:01
417 查看
测试:
配置:
1 在DefaultBeanDefinitionDocumentReader的方法parseBeanDefinitions中对于标签的解析分为默认标签的解析和自定义标签的解析。而默认标签与自定义标签的的区分是根据命名空间来进行判断的。具体代码如下
默认标签的解析分为import、alias、bean、beans;对于beans标签及配置文件的最高父标签,采用深度优先遍历的方式,再次进入parseBeanDefinitions方法中进入解析。
2 bean标签的解析:BeanDefinitionParserDelegate-》parseBeanDefinitionElement
当没有id和name是有一个创建beanName的逻辑,特整理如下。
比如:beanName生成:com.test.service.UserService#0
对、、等子标签的解析,返回GenericBeanDefinition对象,对象中以属性的形式存储各个标签的信息。
BeanDefinitionParserDelegate-》parseBeanDefinitionElement
如上对一个标签进行了解析然后,生成BeanDefinitionHolder对象,构造器为id和包含了标签各种各样的属性值,还有别名。
2 alias标签的解析
alias标签解析基本就是获取name属性和alias属性的值进行环路检测,
应用场景为:
核心代码如下:
说明:比如A->B存在时,不允许出现A->C->B.
未完待续。。。
参考Spring源码深度解析。
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); TextService textService=(TextService)beanFactory.getBean("textService"); textService.sayHello();
配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- 新添加表时要添加 的位置 --> <bean id="textService" class="com.test.service.TextService"> <meta key="msg" value="hello world"/> </bean> </beans>
1 在DefaultBeanDefinitionDocumentReader的方法parseBeanDefinitions中对于标签的解析分为默认标签的解析和自定义标签的解析。而默认标签与自定义标签的的区分是根据命名空间来进行判断的。具体代码如下
BeanDefinitionParserDelegate类 public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans"; public boolean isDefaultNamespace(String namespaceUri) { return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri)); }
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { //默认标签的解析 parseDefaultElement(ele, delegate); } else { //自定义标签的解析 delegate.parseCustomElement(ele); } } } } else { //自定义标签的计息 delegate.parseCustomElement(root); } }
默认标签的解析分为import、alias、bean、beans;对于beans标签及配置文件的最高父标签,采用深度优先遍历的方式,再次进入parseBeanDefinitions方法中进入解析。
2 bean标签的解析:BeanDefinitionParserDelegate-》parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } //如果没有给id赋值,则将第一个name的值赋给id。 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和alias的值与已经解析完成后存于HashSet中的name的值进行比较,即唯一性比较,成功则添加到HashSet中。 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.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); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
当没有id和name是有一个创建beanName的逻辑,特整理如下。
public static String generateBeanName( BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException { String generatedBeanName = definition.getBeanClassName(); if (generatedBeanName == null) { if (definition.getParentName() != null) { generatedBeanName = definition.getParentName() + "$child"; } else if (definition.getFactoryBeanName() != null) { generatedBeanName = definition.getFactoryBeanName() + "$created"; } } if (!StringUtils.hasText(generatedBeanName)) { throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " + "'class' nor 'parent' nor 'factory-bean' - can't generate bean name"); } String id = generatedBeanName; if (isInnerBean) { // Inner bean: generate identity hashcode suffix. id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition); } else { // Top-level bean: use plain class name. // Increase counter until the id is unique. int counter = -1; while (counter == -1 || registry.containsBeanDefinition(id)) { counter++; id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter; } } return id; }
比如:beanName生成:com.test.service.UserService#0
对、、等子标签的解析,返回GenericBeanDefinition对象,对象中以属性的形式存储各个标签的信息。
BeanDefinitionParserDelegate-》parseBeanDefinitionElement
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } //创建一个GenericBeanDefinition对象, AbstractBeanDefinition bd = createBeanDefinition(className, parent); //设置各个属性的值。如class,是否懒加载lazyInit parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //加载各个meta源数据 //如: <bean id="textService" class="com.test.service.TextService"> <meta key="" value=""/> </bean> parseMetaElements(ele, bd); //解析lookup-method标签, http://blog.csdn.net/btwangzhi/article/details/78165862 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //解析replaced-method标签 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析<constructor-arg>标签 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; }
如上对一个标签进行了解析然后,生成BeanDefinitionHolder对象,构造器为id和包含了标签各种各样的属性值,还有别名。
2 alias标签的解析
alias标签解析基本就是获取name属性和alias属性的值进行环路检测,
应用场景为:
核心代码如下:
public boolean hasAlias(String name, String alias) { for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) { String registeredName = entry.getValue(); if (registeredName.equals(name)) { String registeredAlias = entry.getKey(); return (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)); } } return false; }
说明:比如A->B存在时,不允许出现A->C->B.
未完待续。。。
参考Spring源码深度解析。
相关文章推荐
- Spring默认标签解析及注册实现
- Spring源码解密之默认标签的解析
- Spring源码解析:默认标签的解析过程
- spring 源码探索--xml的默认标签解析
- Spring学习(3)——默认标签的解析
- spring默认标签解析
- Spring笔记03-Spring解析默认标签
- Spring源码解析笔记2——默认标签的解析
- Spring源码解析之一 ------ 默认标签的解析注册(IOC的第一步)
- Spring源码解析(2)之默认标签的解析(一)
- Spring源码解析之默认标签的解析
- Spring源码解析(2)之默认标签的解析(二)
- Spring源码解析(四)——默认标签解析
- Spring源码解析-默认标签的解析
- spring源码剖析(二)Spring默认标签解析及注册实现
- Spring解密 - 默认标签的解析
- spring boot 源码解析14-默认错误页面处理流程, 自定义,及EnableAutoConfigurationImportSelector处理
- spring 源码探索--xml的自定义标签解析
- Spring4.3.x 浅析xml配置的解析过程(9)——解析aop命名空间之config标签
- spring 源码探索 -- aop 标签解析和创建代理