dubbo自定义标签

来源:互联网 发布:淘宝上的dota2 编辑:程序博客网 时间:2024/05/17 05:59

一概述

      最近想看看dubbo的实现原理,刚入手代码相关文档提到它与spring框架无缝对接,所以对里面的自定义标签有了兴趣。在spring的配置文件中也经常看到一些很特殊的标签比如spring的事物标签<tx:开头,面向切面处理的<aop:,这里来研究下做个自己的标签怎么玩的。

二xml标签Schema

   要写自己的标签肯定需要有xml的标签规范,所以需要一个schema文件,后缀是.xsd的文件。具体的规范如何编写可以参考 http://www.w3school.com.cn/schema 里面有详细的描述。这里我自己建了一个tag.xsd文件,名字可以自己随意命名,但是后缀必须是xsd的。内容如下:

<?xml version="1.0" encoding="ISO-8859-1" ?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"               targetNamespace="http://aaaa/schema/tag"                         xmlns="http://aaaa/schema/tag"               elementFormDefault="qualified">    <xs:element name="bean">            <xs:complexType>                <xs:attribute name="id" type="xs:string"></xs:attribute>                <xs:attribute name="className" type="xs:string" use="required"></xs:attribute>                <xs:attribute name="scope" type="xs:string" use="optional"></xs:attribute>            </xs:complexType>    </xs:element></xs:schema>
xml的根节点的写法是我从http://www.w3school.com.cn/schema 中拷贝的例子写法。但根节点Schema中的targetNamespace,xmlns属性值是自定义的,之前看别人的写法都是固定的http开头写法以为是需要去某处注册下的http地址,后来自己尝试以后发现这里的属性值只是一个字符串。但是这里的字符串内容必须和spring.schemas文件里面的写法一致。到这里我们的schemas文件已经编写好了,还需要将改规范发布让spring知道有这个规范。这步需要在资源根目录下建META-INF文件夹,在里面建一个spring.schemas的文件,里面有个键值对,内如下:

http\://aaaa/schema/tag/tag.xsd=conf/tag.xsd
这个key就是schema中的targetNamespace标记值,value就是schema文件的保存路径。这时已经在spring中发布了xm的规范,我们开始在xml中使用自己定义的标签。如下:

<beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:aa="http://aaaa/schema/tag"       xsi:schemaLocation="http://www.springframework.org/schema/beans      http://www.springframework.org/schema/beans/spring-beans.xsd      http://aaaa/schema/tag      http://aaaa/schema/tag/tag.xsd">        <aa:bean id="car" className="com.client.haha" scope="1"></aa:bean>        <aa:bean id="user" className="com.client.ClientTest" scope="1"></aa:bean></beans>
在xml中使用自己定义的标签需要引入自定义的规范,如以上的第3行和6,7行的头引入。注意第三行中的aa,这个是可以随意定义的,它就是标签的使用标记。正常引入以后就可以在XML中使用相关的bean标签了。这里要注意相关资源的存放路径,如下图:



三自定义标签解析处理

   到这里我们的自定义标签已经在spring中正常发布了,现在需要能解析自定义标签,并将解析后的bean对象注册到spring容器中。主要涉及到两个类,这两个类都是spring容器中的,需要添加相关依赖。NamespaceHandlerSupport,BeanDefinitionParser。需要通过指定自定义的NamespaceHandlerSupport指定BeanDefinitionParser将自定义的标签进行解析。

public class TagNamespaceHandler extends NamespaceHandlerSupport {    public void init() {        registerBeanDefinitionParser("bean", new TagBeanDefinitionParser());    }}
TagNamespaceHandler类为自定namespaceHandler,里面的“bean”就是我们自定义的标签名字,指明遇到bean标签需要TagBeanDefinitionParser类来解析处理。在spring.handlers串联了自定义的namespaceHandler和schemas,写法如下:

http\://aaaa/schema/tag=com.tag.TagNamespaceHandler

TagBeanDefinitionParser类解析自定义标签处理,并将解析后的RootBeanDefinition注册进入sprin容器中。

public class TagBeanDefinitionParser implements BeanDefinitionParser {    public BeanDefinition parse(Element element, ParserContext parserContext) {        RootBeanDefinition beanDefinition = new RootBeanDefinition();        beanDefinition.setBeanClass(TagBean.class);        beanDefinition.setLazyInit(false);        String id=element.getAttribute("id");        String className=element.getAttribute("className");        beanDefinition.getPropertyValues().add("id",id);        beanDefinition.getPropertyValues().add("className",className);        parserContext.getRegistry().registerBeanDefinition(id,beanDefinition);        return beanDefinition;    }}

标签解析后的数据存储对象

public class TagBean {    private String id;    private String className;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    public String getClassName() {        return className;    }    public void setClassName(String className) {        this.className = className;    }}

加载xml文件,并获取spring容器中的自定义bean容器对象处理

public class TagMain {    public static void main(String[] ags){        String xml = "classpath:applicationContext.xml";        ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { xml });        TagBean tagName=(TagBean)context.getBean("user");        TagBean carName=(TagBean)context.getBean("car");        System.out.println(tagName.getClassName());        System.out.println(carName.getClassName());    }}

执行以上的main函数会加载spring容器,输出xml中的配置数据。

com.client.ClientTest
com.client.haha

四总结

      这样一个简单的自定义标签就做完了,与复杂的标签相比在schemas文件编写复杂一些,但主体的思路是一致的。那么我们常见的spring中用的到<aop:  ,<tx:标签也应该是这么来做的,如果想知道NamespaceHandlerSupport,BeanDefinitionParser的实现原理可以看看spring的源码。


原创粉丝点击