Spring 可扩展XML配置机制

简介

平时我们基于 XML定义Bean 格式如下:


        
        
    

那如果我们想扩展XML Bean的定义和配置呢?如下所示:


此时你就需要了解一下 Spring’s extensible XML configuration mechanism。

官方介绍如下:

Since version 2.0, Spring has featured a mechanism for schema-based extensions to the basic Spring XML format for defining and configuring beans. This section is devoted to detailing how you would go about writing your own custom XML bean definition parsers and integrating such parsers into the Spring IoC container.

To facilitate the authoring of configuration files using a schema-aware XML editor, Spring’s extensible XML configuration mechanism is based on XML Schema.

用过dubbo的同学应该很熟悉下面的配置:


    
    

    
    

    
    

    

    


dubbo官方文档告诉我们 使用 来暴露dubbo服务提供者,使用, 来引用远程服务。那背后究竟做了什么呢?我们如何才能实现跟dubbo类似的呢?

本文着重介绍Spring Framework 基于Schema风格的XML扩展机制,通过Spring提供的xml扩展机制,我们可以在spring.xml中加入自己的标签,之后Spring会帮我们解析并纳入自己的管理范围内。
环境配置

  • JDK 1.7
  • Spring 4.3.6.RELEASE
  • Maven 3.3
  • IDEA 15.0

快速入门

看完 Spring’s extensible XML configuration mechanism,不得不佩服 老外不仅代码写的NB,技术文档写的也非常nice。

本文通过一个简单示例(山寨dubbo 那一套),提供

要实现 XML Bean配置机制,大致分为4步:

  • 编写自己的 XML schema文件;
  • 编写自定义 NamespaceHandler实现类;
  • 编写一个或者多个 BeanDefinitionParser实现类;
  • 注册自定义 XML schema和NamespaceHandler实现类。

1、定义XML schema
首先,我们需要定义一个xsd文件来声明XML标签元素,本文中为 mario.xsd,如下:




    

    
        
            
        
        
    

    
        
            
                
                    
                        
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                
            
        
    

    
        
            
                
                    
                        
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                
            
        
    

    
        
            
                
                    
                        
                    
                    
                    
                    
                    
                    
                    
                
            
        
    

    
        
            
                
                    
                        
                    
                    
                    
                    
                    
                
            
        
    


需要注意两点:

  1. targetNamespace,后面在注册和Spring Bean XML中都会用到;
  2. mario.xsd 文件需放在META-INF目录下。

2、定义NamespaceHandler

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 * ${DESCRIPTION}
 *
 * @author Ricky Fung
 * @create 2016-11-23 11:48
 */
public class MarioNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("service", new MarioServiceBeanDefinitionParser());
        registerBeanDefinitionParser("ref", new MarioReferenceBeanDefinitionParser());
        registerBeanDefinitionParser("registry", new MarioRegistryBeanDefinitionParser());
        registerBeanDefinitionParser("protocol", new MarioProtocolBeanDefinitionParser());
    }
}

3、定义BeanDefinitionParser

定义一个BeanDefinitionParser负责解析上面mario schema中定义的xml标签,如下:

import com.bytebeats.spring4.extension.domain.RpcServiceBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

/**
 * ${DESCRIPTION}
 *
 * @author Ricky Fung
 * @create 2016-11-23 11:50
 */
public class MarioServiceBeanDefinitionParser extends AbstractBeanDefinitionParser {

    @Override
    protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {

        return parseComponet(element, parserContext);
    }

    private AbstractBeanDefinition parseComponet(Element element, ParserContext parserContext) {

        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(RpcServiceBean.class);

        String id = element.getAttribute("id");
        if (StringUtils.hasText(id)) {
            builder.addPropertyValue("id", id);
        }

        String ref = element.getAttribute("ref");
        builder.addPropertyValue("ref", ref);

        String interfaceName = element.getAttribute("interface");
        builder.addPropertyValue("interfaceName", interfaceName);

        String group = element.getAttribute("group");
        if (StringUtils.hasText(group)) {
            builder.addPropertyValue("group", group);
        }

        String registry = element.getAttribute("registry");
        if (StringUtils.hasText(registry)) {
            builder.addPropertyValue("registry", registry);
        }

        String version = element.getAttribute("version");
        if (StringUtils.hasText(version)) {
            builder.addPropertyValue("version", version);
        }

        String timeout = element.getAttribute("timeout");
        if (StringUtils.hasText(timeout)) {
            builder.addPropertyValue("timeout", Integer.parseInt(timeout));
        }

        String retries = element.getAttribute("retries");
        if (StringUtils.hasText(retries)) {
            builder.addPropertyValue("retries", Integer.parseInt(retries));
        }

        String async = element.getAttribute("async");
        if (StringUtils.hasText(async)) {
            builder.addPropertyValue("async", Boolean.valueOf(async));
        }

        return builder.getBeanDefinition();
    }

}

4、注册schema和handler

在META-INF目录下面分别新建spring.handlers和spring.schemas文件。

spring.schemas 如下:

http\://www.bytebeats.com/schema/mario/mario.xsd=/META-INF/mario.xsd

spring.handlers内容如下:

http\://www.bytebeats.com/schema/mario=com.bytebeats.spring4.extension.xml.MarioNamespaceHandler

到这里,所有准备工作都已经完成了,接下来就是如何在 Spring XML配置文件中使用了。

applicationContext.xml




    
    

    
    

    

    

    


参考资料

Spring Extensible XML:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/xml-custom.html

你可能感兴趣的:(Spring 可扩展XML配置机制)