2. Xml 标签解析
前面讲到,Xml中的标签分为两种,一种是Spring默认标签,例如 <bean id="bookService" class="com.newcoder.api.BookService">,另一种是自定义标签,例如 <mvc:annotation-driven />,这一节,我们就来看看默认标签和自定义标签的解析方法。
一、默认标签解析
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { // import标签解析 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } // Alias标签解析 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } // bean标签解析 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } // beans标签解析,使其作为root,循环调用文件解析(回忆一下,整个applicationContext.xml本身不就是一个beans么?) else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
1. Bean标签解析
1. 元素解析
2. 如果默认标签下存在自定义标签,则需要对其进行解析
3. 对解析后的bdHolder进行注册
4. bean加载完成,通知相关监听器
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 1. 元素解析 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // 2. 如果默认标签下存在自定义标签,则需要对其进行解析 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 3. 对解析后的bdHolder进行注册 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // 4. bean加载完成,通知相关监听器 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
1.1. 元素解析
1. 解析 id, name 属性
2. 校验 name 的重复性
3. 创建 BeanDefinition
3.1 创建一个BeanDefinition(该对象上属性与bean标签中属性一一对应)
3.2 解析所有属性并将其赋值在BeanDefinition上
4. 如果 beanName 为空,则生成默认的 beanName
5. 将 BeanDefinition 封装进 BeanDefinitionHolder 中返回
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // 获取id String id = ele.getAttribute(ID_ATTRIBUTE); // 获取name(如果想用多个别名,使用逗号或分号连接) 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)); } 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"); } } // bean名称不能重复 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // 创建BeanDefinition 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); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. 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; } } // 将BeanDefinition封装进BeanDefinitionHolder中 String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
下面来分析下 BeanDefinition 的创建过程:
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { // 1. 使用Stack存储 this.parseState.push(new BeanEntry(beanName)); // 2. 解析class、parent属性 // 2.1 解析class属性 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { // 2.2 解析parent属性 String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } // 3. 创建GenericBeanDefinition对象,将class信息放进去 AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 4. 解析Bean各种属性,赋到BeanDefinition中 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // 5. 提取description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); // 6. 解析子元素meta parseMetaElements(ele, bd); // 7. 解析子元素lookup-method parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // 8. 解析子元素replaced-method parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 9. 解析子元素constructor-arg parseConstructorArgElements(ele, bd); // 10. 解析子元素property parsePropertyElements(ele, bd); // 11. 解析子元素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; }
1.2 解析默认标签下的自定义标签
1. 循环遍历属性,如果有自定义标签,则解析
2. 循环遍历子节点,如果有自定义标签,则解析
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { return decorateBeanDefinitionIfRequired(ele, definitionHolder, null); } // containingBd:父类的BeanDefinition,如果子类没有设置scope,默认使用父类的scope public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; // 对属性中的自定义标签进行解析 NamedNodeMap attributes = ele.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node node = attributes.item(i); finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } // 对子节点中的自定义标签进行解析 NodeList children = ele.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } } return finalDefinition; } public BeanDefinitionHolder decorateIfRequired( Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(node); // 如果不是默认标签,则使用NamespaceHandler进行解析(自定义标签解析) if (!isDefaultNamespace(namespaceUri)) { NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler != null) { return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd)); } else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node); } else { // A custom namespace, not to be handled by Spring - maybe "xml:...". if (logger.isDebugEnabled()) { logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]"); } } } return originalDef; }
1.3 对解析后的 bdHolder 进行注册
这里的注册分为两部分,第一部分是beanName与BeanDefinition的注册,用于通过beanName找到BeanDefinition;第二部分是aliases与beanName的注册,将所有的别名绑定到beanName上。
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // 通过beanName进行注册,<beanName, BeanDefinition> String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 通过别名进行注册 <alais, beanName> String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
1.4 bean加载完成,通知相关监听器
当BeanDefinition注册完成之后,调用监听此事件的程序。Spring在这里的实现是空的,开发人员可以自己实现扩展。
public void fireComponentRegistered(ComponentDefinition componentDefinition) { this.eventListener.componentRegistered(componentDefinition); }
2. import标签解析
1. 获取 import 标签中的 resource 属性
2. 替换掉 location 中的系统参数
3. 判断 location 是绝对路径还是相对路径
3.1 绝对路径,直接读取,然后递归调用xml文件解析
3.2 相对路径,先转换为绝对路径再读取,然后递归调用文件xml解析
4. 解析完成,通知相关监听器
protected void importBeanDefinitionResource(Element ele) { // 1. 解析 resource 属性,拿到文件地址 String location = ele.getAttribute(RESOURCE_ATTRIBUTE); if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } // 对文件地址中的系统参数进行替换,例如:"${user.dir}" location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<Resource>(4); // 判断location是 绝对路径 还是 相对路径 boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { // cannot convert to an URI, considering the location relative // unless it is the well-known Spring prefix "classpath*:" } // 如果是绝对路径,直接根据地址加载对应的配置文件 if (absoluteLocation) { try { int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) { getReaderContext().error( "Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } else { // 如果是相对路径,则根据相对地址计算出绝对地址 try { int importCount; Resource relativeResource = getReaderContext().getResource().createRelative(location); if (relativeResource.exists()) { importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); actualResources.add(relativeResource); } else { String baseLocation = getReaderContext().getResource().getURL().toString(); importCount = getReaderContext().getReader().loadBeanDefinitions( StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isDebugEnabled()) { logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]"); } } catch (IOException ex) { getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } // 解析完成后通知相关监听器 Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]); getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele)); }
3. Alias标签解析
1. 属性解析:beanName、alias
2. 建立别名映射
protected void processAliasRegistration(Element ele) { // 获取beanName String name = ele.getAttribute(NAME_ATTRIBUTE); // 获取alias String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; if (!StringUtils.hasText(name)) { getReaderContext().error("Name must not be empty", ele); valid = false; } if (!StringUtils.hasText(alias)) { getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) { try { // 注册alias到beanName的映射,<alias, beanName> getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception ex) { getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, ex); } getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); } }
4. beans标签解析
看,我们一直解析的就是 beans 啊!
那么如果在文件里再遇到 beans 怎么办,就把它当作单独的配置文件解析不就完了么。
二、自定义标签解析
自定义标签的定义及使用请移步到 基于Spring可扩展Schema提供自定义配置支持(spring配置文件中 配置标签支持)。
自定义标签解析分为三个过程:
1. 获取节点的命名空间
2. 根据命名空间找到 NamespaceHandler
3. 通过 NamespaceHandler 解析节点
1. 获取节点命名空间
这里不用多说,命名空间就是节点的uri。
public String getNamespaceURI(Node node) { return node.getNamespaceURI(); }
2. 根据命名空间找到 NamespaceHandler
1. 获取所有已配置的handlers映射(第一次从 Spring.handlers 中加载,存在map中)
2. 如果通过 handlerMappings 直接可以获得 Namespacehandler 对象,则直接返回
3. 首次加载NamespaceHandler,实例化对象后放入handlerMappings中,覆盖掉之前的class全路径,之后就不用再创建了
3.1 调用自定义的 init 方法,用于注册 BeanDefinitionParser 解析器。
public NamespaceHandler resolve(String namespaceUri) { // 1. 获取所有已配置的handler映射(第一次从Spring.handlers中加载,然后存在map中) Map<String, Object> handlerMappings = getHandlerMappings(); Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } // 2. 如果获取到NamespaceHandler,直接返回(首次获取到NamespaceHandler后会将其放进handlerMappings中) else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { // 3. 首次加载NamespaceHandler,实例化对象后放入handlerMappings中,覆盖掉之前的class全路径,之后就不用再创建了 String className = (String) handlerOrClassName; try { Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); // 调用自定义的init方法,也就是registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser),用来绑定BeanDefinitionParser解析器 namespaceHandler.init(); handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } catch (ClassNotFoundException ex) { throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", ex); } catch (LinkageError err) { throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", err); } } }
3. 通过 Namespace 进行解析
我们看 parse(..) 方法,这里分为两步,第一是根据节点找到对应的解析器,第二是使用该解析器解析该节点。
public BeanDefinition parse(Element element, ParserContext parserContext) { // 1. 寻找解析器 // 2. 解析该节点 return findParserForElement(element, parserContext).parse(element, parserContext); }
3.1 寻找节点对应的解析器
首先是获取元素名称,这里的名称是指 <context:component-scan> 中的 component-scan。
然后从之前的注册器(Map) 中获取parser。
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { // 获取元素名称 String localName = parserContext.getDelegate().getLocalName(element); // 根据元素名称获取解析器(还记得之前在init方法中注册了解析器么?) BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
3.2 使用解析器进行解析
1. 标签解析并转换为 BeanDefinition
1.1 使用 Builder 模式,创建 BeanDefinitionBuilder
1.2 通过自定义解析器的覆写方法获取 beanClass 或 beanClassName
1.3 如果存在父类,则使用父类的 scope
1.4 如果父类时懒加载,那么它也是懒加载
1.5 调用自定义解析器腹泻的 doParse(..) 方法完成解析
1.6 使用 Builder 模式创建 BeanDefinition
2. 获取别名
3. 创建 BeanDefinitionHolder 并注册
4. 通知相关监听器
public final BeanDefinition parse(Element element, ParserContext parserContext) { // 1. 标签解析并转换为BeanDefinition AbstractBeanDefinition definition = parseInternal(element, parserContext); if (definition != null && !parserContext.isNested()) { try { String id = resolveId(element, definition, parserContext); if (!StringUtils.hasText(id)) { parserContext.getReaderContext().error( "Id is required for element '" + parserContext.getDelegate().getLocalName(element) + "' when used as a top-level tag", element); } // 2. 获取别名(这里的shouldParseNameAsAliases()固定返回true) String[] aliases = null; if (shouldParseNameAsAliases()) { String name = element.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(name)) { aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); } } // 3. 创建BeanDefinitionHolder并注册,这里的id对应beanName BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases); registerBeanDefinition(holder, parserContext.getRegistry()); // 4. 通知相关监听器(shouldFireEvents()固定返回true) if (shouldFireEvents()) { BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder); // 解析后处理,自己扩展实现 postProcessComponentDefinition(componentDefinition); parserContext.registerComponent(componentDefinition); } } catch (BeanDefinitionStoreException ex) { parserContext.getReaderContext().error(ex.getMessage(), element); return null; } } return definition; } protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { // 创建BeanDefinition的Builder(Builder模式) BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); String parentName = getParentName(element); if (parentName != null) { builder.getRawBeanDefinition().setParentName(parentName); } // 获取class属性,调用自定义解析器中覆盖的 getBeanClass(..)方法 Class<?> beanClass = getBeanClass(element); if (beanClass != null) { builder.getRawBeanDefinition().setBeanClass(beanClass); } else { // 如果自定义解析器没有覆盖getBeanClass(..)方法,则检查有没有覆盖getBeanClassName(..)方法 String beanClassName = getBeanClassName(element); if (beanClassName != null) { builder.getRawBeanDefinition().setBeanClassName(beanClassName); } } builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); // 如果存在父类,则使用父类的scope if (parserContext.isNested()) { builder.setScope(parserContext.getContainingBeanDefinition().getScope()); } // 如果父类是懒加载,那么它也是懒加载 if (parserContext.isDefaultLazyInit()) { builder.setLazyInit(true); } // 调用自定义解析器中的doParser(..)方法进行解析 doParse(element, parserContext, builder); // 使用Builder模式创建BeanDefinition return builder.getBeanDefinition(); }