天天看點

Dubbo|基礎知識之解析自定義标簽流程

Dubbo架構内自定義很多XML标簽,友善以XML方式注冊服務;本篇文章先了解下Dubbo架構擁有哪些XML标簽,然後給出自定義标簽的流程并動手自定義标簽。

1.Dubbo架構中的那些标簽

Dubbo架構标簽定義的源檔案是dubbo.xsd,該檔案位于dubbo.jar内

/META-INF/

目錄下;源檔案内容太多就不一一列出來,不過從dubbo.xsd得知Dubbo擁有以下15個标簽:

annotation,application,module,registry,metadata-report,config-center,monitor,protocol,service,provider,consumer,reference,method,argument,parameters

,每個标簽都定義好各自的元素,元素幾乎與各标簽對應的實體類的屬性相對應。

下面是使用dubbo自定義标簽的一個例子。

Dubbo|基礎知識之解析自定義标簽流程

為了後面更好的學習Dubbo架構定義标簽的使用和解析,我們有必要了解标簽自定義的過程。

2.自定義标簽的流程

  • 定義标簽實體類和.xsd檔案
  • 聲明标簽的命名空間及其處理類
  • 聲明标簽的解析邏輯
  • 編寫測試類

3.動手自定義标簽

3.1 定義标簽實體類和.xsd檔案

标簽實體類Person:

public class Person {
    private String name;
    private String age;
    private int sex;
    private boolean flag;
    
    // 省略set get方法,toString方法
}
           

定義person.xsd檔案

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
        xmlns="http://www.starry.net/schema/person"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:beans="http://www.springframework.org/schema/beans"
        targetNamespace="http://www.starry.net/schema/person"
        elementFormDefault="qualified"
        attributeFormDefault="unqualified">
    <xsd:import namespace="http://www.springframework.org/schema/beans" />
    <!-- 定義element名, personType對應了bean的屬性  -->
    <xsd:element name="person" type="personType">
        <xsd:annotation>
            <xsd:documentation><![CDATA[ The person config ]]></xsd:documentation>
        </xsd:annotation>
    </xsd:element>
    <!--  配置各屬性值,有點像Mybatis配置對應的model   -->
    <xsd:complexType name="personType">
        <xsd:attribute name="id" type="xsd:ID">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="name" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The person name. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="age" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The person age. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="sex" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The person sex. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="flag" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The person flag. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
    </xsd:complexType>

</xsd:schema>
           

person.xsd檔案中的标簽中繼資料對應Person.class類中的屬性;.xsd檔案中element的name值就是xml檔案中使用的标簽名,attribute的name值則是标簽對應的屬性元素。注意attribute的type值,不需要與實體類中屬性的類型一緻,統一寫成string類型。

person.xsd檔案放置在/resources目錄下。

3.2 聲明标簽的命名空間及其處理類

person.xsd檔案既然定義好了,那麼如何使用呢?在xml檔案頭部通過自定義命名空間(xml name space)指定.xsd檔案的schemasLocation,由該schemasLocation指定.xsd檔案的位置。spring約定命名空間位址寫在

/META-INF/spring.handlers

檔案内,并且指定該命名空間的處理類,即此處的PersonNamespaceHandler.class。

http\://www.starry.net/schema/person=com.starry.bean.handler.PersonNameSpaceHandler
           

等号左邊是

自定義的命名空間位址

,可以随便定義;等号右邊是

自定義命名空間處理類的類路徑名

編寫自定義命名空間處理類PersonNamespaceHandlers.class

package com.starry.bean.handler;

import com.starry.bean.parse.PersonBeanDefinitionParser;
import com.starry.custom.label.Person;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class PersonNameSpaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("person", new PersonBeanDefinitionParser(Person.class, true));
    }
}
           

命名空間指定.xsd檔案的schemasLocation,一般都是配套寫在xml檔案的頭部(命名空間位址和schemasLocation之間用空格或者換行隔開);spring約定schemaLocation寫在

/META-INF/ spring.schemas

檔案内,由schemationLocation位址指定person.xsd檔案的位置。

http\://www.starry.net/schema/person/person.xsd=person.xsd
           

等号左邊是

約定的schemasLocation位址

,它需要與上面定義的命名空間位址一緻;等号右邊則是

person.xsd在項目中的位置

,如果放置在/META-INF目錄下,則需要指定目錄為“/META-INF/person.xsd”。

3.3 聲明标簽的解析邏輯

在命名空間處理類PersonNamespaceHandler中有一個名為PersonBeanDefinitionParser類,該類是解析xml檔案person标簽的邏輯。

package com.starry.bean.parse;

import com.starry.custom.label.Person;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;


public class PersonBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    private final Class<?> beanClass;
    private final boolean required;

    public PersonBeanDefinitionParser(Class<?> beanClass, boolean required) {
        this.beanClass = beanClass;
        this.required = required;
    }

    protected Class getBeanClass(Element element) {
        return Person.class;
    }

    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String name = element.getAttribute("name");
        String age = element.getAttribute("age");
        String sex = element.getAttribute("sex");
        String flag = element.getAttribute("flag");
        if (StringUtils.hasText(name)) {
            builder.addPropertyValue("name", name);
        }

        if (StringUtils.hasText(age)) {
            builder.addPropertyValue("age", age);
        }

        if (StringUtils.hasText(sex)) {
            builder.addPropertyValue("sex", Integer.valueOf(sex));
        }

        if (StringUtils.hasText(flag)) {
            builder.addPropertyValue("flag", Boolean.valueOf(flag));
        }
    }
}
           

繼承AbstractSingleBeanDefinitionParser類,重寫doParse(Element,BeanDefinitionBuilder)方法,定義簡單的解析邏輯。

3.4 編寫測試類

建立person.xml檔案,引入perosn命名空間以及schemasLocation;然後聲明一個person标簽的對象。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:test="http://www.starry.net/schema/person"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
         http://www.starry.net/schema/person
         http://www.starry.net/schema/person/person.xsd">

    <test:person id="a" name="xiaoMing" age="25" sex="1" flag="true" />

</beans>
           

xmlns:test="http://www.starry.net/schema/person"表示在person.xml檔案内用test指定為person命名空間位址的簡稱,是以就有了test:perosn。person是person.xsd檔案内定義的element名稱,也是PersonNamespaceHandler.class處理person命名空間的依據。

注意:id屬性是每個标簽都有的,可以聲明也可以省略。

編寫test類,擷取容器中person對象并列印出來。

package com.starry;

import com.starry.custom.label.Person;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("person.xml");
        Person person =  context.getBean(Person.class);
        System.out.println(person.toString());
    }
}
           

執行結果表明person.xml檔案内test:person标簽的内容已經被初始化為容器内的bean,是以自定義标簽person成功。

4.思考

早在第二小節就給出了自定義标簽的具體步驟,也是為了幫助不熟悉自定義标簽的讀者更好的了解這個過程;在第三節的示範過程中,詳細說明每個步驟的作用和含義,雖然最終實踐成功,但是你可能好奇PersonNamespaceHandler和PersonDefinitionParser類在自定義标簽解析的過程中是如何執行的,或者說什麼時候被執行的。

要想了解上面的問題,就必須深入ClassPathXmlApplicationContext類的初始化過程,這個過程我們在剖析Dubbo自定義标簽解析流程中會深入分析,這裡我們對自定義标簽的流程有一個認識就OK了。

繼續閱讀