基于Spring开发——自定义标签及其解析

 

1. XML Schema

1.1 最简单的标签

一个最简单的标签,形式如:

<bf:head-routing key="1" value="1" to="test2"/>

该标签只包含了若干属性,我们就在xsd文件中这么定义

<!-- 声明一个标签,名字为head-routing,他的类型为headRouting-->
<xsd:element name="head-routing" type="headRouting"></xsd:element>

    <!--  定义head-routing的类型,这里定义它有key,value,to,patten四个属性 -->
    <xsd:complexType name="headRouting">
        <xsd:attribute name="key" type="xsd:string" use="required"></xsd:attribute>
        <xsd:attribute name="value" type="xsd:string" use="required"></xsd:attribute>
        <xsd:attribute name="to" type="xsd:IDREF" use="required"></xsd:attribute>
        <xsd:attribute name="patten" type="xsd:string" default="string"></xsd:attribute>
    </xsd:complexType><xsd:attribute>标签
中的type是用来定义该属性的格式,例如
  • xsd:string 表示是一个字符串,对格式没什么要求
  • xsd:id 表示该属性的值是一个id,有格式要求(例如不能以数字开头)。
  • xsd:IDREF 表示该属性的值与某xsd:id属性的值对应
  • 其他还有很多,例如number,double,datetime等等。

1.2 复杂点的标签

所谓复杂,其实就是嵌套的标签,形式如:

    <bf:stop id="test1" ref="testNode">
        <bf:head-routing key="1" value="1" to="test2"/>
    </bf:stop>

其实只要参照Spring 中<bean>标签的xsd依葫芦画瓢,首先是定义stop标签

    <xsd:element name="stop">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:group ref="stopElements"/>
                    <xsd:attributeGroup ref="stopAttributes"/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>

其中,

  • <xsd:extension base="beans:identifiedType"> 定义了该标签的id属性,注意这里引用的是spring-beans中的type,
  • <xsd:group ref="stopElements"/>中定义了<bf:stop>标签允许的子标签
  • <xsd:attributeGroup ref="stopAttributes"/> 定义了<bf:stop>标签允许的属性
    <xsd:group name="stopElements">
        <xsd:sequence>
            <xsd:element ref="description" minOccurs="0"/>
            <xsd:choice minOccurs="0" maxOccurs="unbounded">
                <xsd:element ref="head-routing"/>
                  <!-- 有更多的子标签继续在这里添加,例如<xsd:element ref="properties"/> -->
            </xsd:choice>
        </xsd:sequence>
    </xsd:group>


    <xsd:attributeGroup name="stopAttributes">
        <xsd:attribute name="ref" type="xsd:IDREF" use="required">
            <xsd:annotation>                 
                <xsd:appinfo>
                      <!-- 这里是使用了Spring tool xsd中的标签,格式校验-->
                    <tool:annotation kind="ref">
                        <tool:expected-type type="com.lizo.node.Station"/>
                    </tool:annotation>
                </xsd:appinfo>
            </xsd:annotation>
        </xsd:attribute>
        <!-- 有更多的子标签继续在这里添加,例如<xsd:attribute name="value" type="xsd:string"/> -->

2. 配置文件

完成了xsd文件编写后,还需要让该文件生效,就需要在项目的resource/META-INF包里面配置2个文件spring.handlers和spring.schemas

2.1 spring.schemas

改配置文件主要是用一个url来映射我们第一步配置好的文件,形式如下

http://www.lizo.com/schema/bf.xsd=META-INF/bf.xsd

这样,就可以在Spring的xml配置文件中加入spring.schemas的url,省略掉其他的,在<beans>标签中增加如下信息

    <beans
        ..
       xmlns:bf="http://www.lizo.com/schema/bf"
       xsi:schemaLocation="
        ...
        http://www.lizo.com/schema/bf
        http://www.lizo.com/schema/bf.xsd
        ">

完成这步以后,就可以在xml中写自己的标签了,例如自定义标签的namespace为bf,

   <bf:stop id="test123" ref="testNode">
        <bf:head-routing key="1" value="1" to="test1"/>
        <bf:head-routing key="3" value="4" to="test2"/>
    </bf:stop>

2.2 spring.handlers

这个配置文件用来配置解析我们bf标签,然后生成一些BeanDefinition进行注册。例如

http://www.lizo.com/schema/bf=com.lizo.config.BusinessFlowNamespaceHandlerSupport

其中 BusinessFlowNamespaceHandlerSupport就是我们用来解析标签

3. 自定义标签解析

在上一步中,我们配置了com.lizo.config.BusinessFlowNamespaceHandlerSupport类作为解析自定义标签的类,所以namespace为bf的标签,都会用这里注册的标签解析器来解析

public class BusinessFlowNamespaceHandlerSupport extends NamespaceHandlerSupport {
    public void init() {
        //注册用于解析<bf:stop>的解析器
        registerBeanDefinitionParser("stop", new BusinessFlowBeanDefinitionParser());
    }
}

我们自定义的标签解析器BusinessFlowBeanDefinitionParser是要实现BeanDefinitionParser 接口的

public interface BeanDefinitionParser {
    BeanDefinition parse(Element element, ParserContext parserContext);
}

一般来说,注册bean的基本流程为:

  1. 解析标签
  2. 根据解析的值生成BeanDefinition,
  3. 注册标签

解析标签就不用说,重点说说怎么生成BeanDefinition

3.1 生成BeanDefinition

一个最简单的BeanDefinition通过设置Class和属性的注入就可以完成。如下:

RootBeanDefinition nodeWrapDefinition = new RootBeanDefinition();
//该BeanDefinition对应的是什么类
nodeWrapDefinition.setBeanClass(StationRoutingWrap.class);
//name是解析标签后获得的值
nodeWrapDefinition.getPropertyValues().addPropertyValue("name", name);

RuntimeBeanReference

RuntimeBeanReference 用于在运行时去获取BeanDefinition,因为在我们创建这个BeanDefinition的时候我们只知道他的beanName,并不确定是否已经注册了,这个时候就需要用RuntimeBeanReference,例如

RuntimeBeanReference refBean = new RuntimeBeanReference(ref);
        nodeWrapDefinition.getPropertyValues().addPropertyValue("station", refBean);

集合类BeanDefinition

某个BeanDefinition注入的属性为一个List,这个时候就需要用ManagedList(同理有ManagedMap,ManagedSet),

ManagedList routingConditions = new ManagedList();
....
nodeWrapDefinition.getPropertyValues().add("routing", routing);

3.2 注册bean

注册BeanDefinitionParser 接口的函数中有个参数ParserContext,有个方法为getRegistry(),因此,注冊bean的時候就很简单了

parserContext.getRegistry().registerBeanDefinition("beanName",nodeWrapDefinition);

总结

通过以上三步,就可以实现自己定义标签,并且在Spring容器中注入相关的bean。让我们的框架使用起来更方便(更装B)

原文地址:https://www.cnblogs.com/lizo/p/6683606.html