Spring的XML解析原理,这一次全搞懂再走( 八 )

看到这里我们应该就清楚了Spring是如何解析xml里的标签了以及我们如果要扩展自己的标签该怎么做 。 只需要创建一个我们的自定义标签和解析类 , 并指定它的命名空间以及NamespaceHandler , 最后在META-INF/spring.handlers文件中指定命名空间和NamespaceHandler的映射关系即可 , 就像Spring的c和p标签一样:
http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandlerhttp\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler像这样使用SPI的思想设计我们的项目的话 , 当需要扩展时 , 不需要改动任何的代码 , 非常的方便优雅 。 接着 , 我们回到handler的decorate方法 , 这里有三个默认的实现类:NamespaceHandlerSupport、SimpleConstructorNamespaceHandler、SimplePropertyNamespaceHandler 。 第一个是一个抽象类 , 与我们这里的流程无关 , 感兴趣的可自行了解 , 第二个和第三个则分别是c和p标签对应的NamespaceHandler , 两个装饰的处理逻辑基本上是一样的 , 我这里进入的是SimpleConstructorNamespaceHandler类:
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {if (node instanceof Attr) {Attr attr = (Attr) node;String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr));String argValue = http://kandian.youth.cn/index/StringUtils.trimWhitespace(attr.getValue());ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues();boolean ref = false;// handle -ref argumentsif (argName.endsWith(REF_SUFFIX)) {ref = true;argName = argName.substring(0, argName.length() - REF_SUFFIX.length());}ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue);valueHolder.setSource(parserContext.getReaderContext().extractSource(attr));// handle"escaped"/"_" argumentsif (argName.startsWith(DELIMITER_PREFIX)) {String arg = argName.substring(1).trim();// fast default checkif (!StringUtils.hasText(arg)) {cvs.addGenericArgumentValue(valueHolder);}// assume an index otherwiseelse {int index = -1;try {index = Integer.parseInt(arg);}catch (NumberFormatException ex) {parserContext.getReaderContext().error("Constructor argument '" + argName + "' specifies an invalid integer", attr);}if (index < 0) {parserContext.getReaderContext().error("Constructor argument '" + argName + "' specifies a negative index", attr);}if (cvs.hasIndexedArgumentValue(index)) {parserContext.getReaderContext().error("Constructor argument '" + argName + "' with index "+ index+" already defined using ." +" Only one approach may be used per argument.", attr);}cvs.addIndexedArgumentValue(index, valueHolder);}}// no escaping -> ctr nameelse {String name = Conventions.attributeNameToPropertyName(argName);if (containsArgWithName(name, cvs)) {parserContext.getReaderContext().error("Constructor argument '" + argName + "' already defined using ." +" Only one approach may be used per argument.", attr);}valueHolder.setName(Conventions.attributeNameToPropertyName(argName));cvs.addGenericArgumentValue(valueHolder);}}return definition; }