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架構定義标簽的使用和解析,我們有必要了解标簽自定義的過程。
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了。