欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring源码解析之自定义标签的解析

程序员文章站 2022-05-23 18:27:41
...

阅读须知

  • Spring源码版本:4.3.8
  • 文章中使用/* */注释的方法会做深入分析

正文

上篇文章我们介绍了Spring默认标签的解析,本文我们来分析一下Spring自定义标签的解析。上篇文章我们了解到Spring的默认标签目前有4个(import、alias、bean、beans),也就是说除了这4个标签以外的标签都是自定义标签(当然这里所说的标签不包括那些以子标签形式存在的如property、value等标签),如我们熟知的事务标签<tx:annotation-driven/>、注解扫描标签<context:component-scan/>等都属于自定义标签,下面就让我们来分析一下这些自定义标签是如何解析的,承接Spring源码解析之默认标签的解析文中自定义标签解析的分支:
BeanDefinitionParserDelegate:

public BeanDefinition parseCustomElement(Element ele) {
    /* 解析自定义元素 */
    return parseCustomElement(ele, null);
}

BeanDefinitionParserDelegate:

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    // 获取命名空间
    String namespaceUri = getNamespaceURI(ele);
    /* 根据命名空间获取NamespaceHandler */
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    /* 解析自定义标签 */
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

DefaultNamespaceHandlerResolver:

public NamespaceHandler resolve(String namespaceUri) {
    /* 获取所有已经配置的handler映射 */
    Map<String, Object> handlerMappings = getHandlerMappings();
    // 根据命名空间找到对应的映射
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        return null;
    }
    else if (handlerOrClassName instanceof NamespaceHandler) {
        // 如果已经实例化过,直接返回
        return (NamespaceHandler) handlerOrClassName;
    }
    else {
        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);
            namespaceHandler.init(); // 调用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);
        }
    }
}

DefaultNamespaceHandlerResolver:

private Map<String, Object> getHandlerMappings() {
    if (this.handlerMappings == null) {
        synchronized (this) {
            if (this.handlerMappings == null) {
                try {
                    // 加载配置
                    Properties mappings =
                            PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                    }
                    Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
                    // 放入缓存
                    CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                    this.handlerMappings = handlerMappings;
                }
                catch (IOException ex) {
                    throw new IllegalStateException(
                            "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
                }
            }
        }
    }
    return this.handlerMappings;
}

这里就是加载配置文件到内存中,而this.handlerMappingsLocation在调用构造方法初始化时被赋值为META-INF/Spring.handlers,我们来看一下Spring事务自定义标签对应这里的配置,锁定spring-tx包下的META-INF/Spring.handlers:

http\:// www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

所以在解析Spring事务自定义标签时就会找到TxNamespaceHandler并调用其init方法:

public void init() {
    registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
    registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
    registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}

init方法就是注册对应三个标签的解析器,这里用Spring事务标签举例,其他自定义标签大同小异。下面就是解析过程:
NamespaceHandlerSupport:

public BeanDefinition parse(Element element, ParserContext parserContext) {
    /* 寻找解析器进行解析 */
    return findParserForElement(element, parserContext).parse(element, parserContext);
}

NamespaceHandlerSupport:

private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    // 以<tx:annotation-driven/>为例,这里的localName就是annotation-driven
    String localName = parserContext.getDelegate().getLocalName(element);
    // 根据localName获取解析器,上面注册过annotation-driven的解析器
    BeanDefinitionParser parser = this.parsers.get(localName);
    if (parser == null) {
        parserContext.getReaderContext().fatal(
                "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
    }
    return parser;
}

获取到BeanDefinitionParser后,调用其parse方法进行解析,解析的过程就是根据开发者需求的不同自行实现了,整体来说就是解析配置到注册BeanDefinition的过程。到这里自定义标签的解析就完成了。