基於Spring開發——自定義標籤及其解析

1. XML Schema

要想自定義標籤,首先第一步須要寫本身的XML Schema。XML Schema的我的感受比較複雜,網上的教程比較簡單,所以能夠參照spring-beans.xsd依葫蘆畫瓢。這裏就按照我本身的理解進行簡單介紹一下吧。 ##1.1 最簡單的標籤 一個最簡單的標籤,形式如:node

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

該標籤只包含了若干屬性,咱們就在xsd文件中這麼定義spring

<!-- 聲明一個標籤,名字爲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是用來定義該屬性的格式,例如app

  • 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標籤ide

<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.schemasui

2.1 spring.schemas

改配置文件主要是用一個url來映射咱們第一步配置好的文件,形式以下url

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

這樣,就能夠在Spring的xml配置文件中加入spring.schemas的url,省略掉其餘的,在<beans>標籤中增長以下信息spa

<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,code

<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)

相關文章
相關標籤/搜索