spring自定义xml标签

来源:互联网 发布:淘宝买的散装卫生巾 编辑:程序博客网 时间:2024/06/10 04:02

spring自定义xml标签

要实现自定义的xml配置,需要有两个默认spring配置文件来支持。一个是spring.schemas,一个是spring.handlers,前者是为了验证你自定义的xml配置文件是否符合你的格式要求,后者是告诉spring该如何来解析你自定义的配置文件。

自定义标签涉及的核心接口为:

  • NamespaceHandler
  • BeanDefinitionParser

实际使用的时候,一般分别继承类:

  • NamespaceHandlerSupport:init
  • AbstractSingleBeanDefinitionParser:parse

以spring事务标签为例(前提:要了解bean注册过程):

1. 配置文件:

  • spring.handlers
    spring.handlers

  • spring.schemas
    spring.schemas

2. 调用逻辑

调用逻辑

  • 在第3步中 registerBeanDefinitions 调用 createReaderContext
    //class XmlBeanDefinitionReader    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();        int countBefore = getRegistry().getBeanDefinitionCount();        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));        return getRegistry().getBeanDefinitionCount() - countBefore;    }
  • 第4步 createReaderContext 中调用getNamespaceHandlerResolver方法获取: NamespaceHandlerResolver
    //class XmlBeanDefinitionReader    public XmlReaderContext createReaderContext(Resource resource) {        return new XmlReaderContext(resource, this.problemReporter, this.eventListener,                this.sourceExtractor, this, getNamespaceHandlerResolver());    }    public NamespaceHandlerResolver getNamespaceHandlerResolver() {        if (this.namespaceHandlerResolver == null) {            this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();        }        return this.namespaceHandlerResolver;    }

new 一个 DefaultNamespaceHandlerResolver

    //class XmlBeanDefinitionReader    protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {        return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());    }

DEFAULT_HANDLER_MAPPINGS_LOCATION: META-INF/spring.handlers

    //DefaultNamespaceHandlerResolver    public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {        this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);    }    public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {        Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");        this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());        this.handlerMappingsLocation = handlerMappingsLocation;    }

DefaultNamespaceHandlerResolver的属性:private volatile Map handlerMappings保存的是
namespace URI 与 NamespaceHandler的映射

handlerMappings

  • 第5步调用DefaultBeanDefinitionDocumentReader(父类BeanDefinitionDocumentReader)的 registerBeanDefinitions 方法
    //BeanDefinitionDocumentReader    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {        this.readerContext = readerContext;        logger.debug("Loading bean definitions");        Element root = doc.getDocumentElement();        doRegisterBeanDefinitions(root);    }    protected void doRegisterBeanDefinitions(Element root) {        BeanDefinitionParserDelegate parent = this.delegate;        this.delegate = createDelegate(getReaderContext(), root, parent);        if (this.delegate.isDefaultNamespace(root)) {            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);            if (StringUtils.hasText(profileSpec)) {                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {                    if (logger.isInfoEnabled()) {                        logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +                                "] not matching: " + getReaderContext().getResource());                    }                    return;                }            }        }        preProcessXml(root);        parseBeanDefinitions(root, this.delegate);        postProcessXml(root);        this.delegate = parent;    }

delegate.parseCustomElement(ele); 这一行代码是解析自定义标签

    //class DefaultBeanDefinitionDocumentReader    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);        }    }
  1. 根据元素标签获取:NamespaceHandler,并调用其 init 方法
  2. 调用 NamespaceHandler 的 parse 方法,在 parse 方法里解析标签,然后返回BeanDefinition,后续会被spring注册
    //class BeanDefinitionParserDelegate    public BeanDefinition parseCustomElement(Element ele) {        return parseCustomElement(ele, null);    }    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {        String namespaceUri = getNamespaceURI(ele);        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));    }

3. 定制点

  • 定制 init 方法:一般在init方法中注册BeanDefinitionParser, 存储在其父类NamespaceHandlerSupport的属性:parsers 中

init

  • 定制 parse 方法:一般在parse方法中返回BeanDefinition

parse