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了。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容