Spring的自定義標(biāo)簽

Spring為自定義xml標(biāo)簽加載提供了擴(kuò)展伍派。用戶(hù)可自定義標(biāo)簽并注冊(cè)到Spring的bean容器中江耀。實(shí)現(xiàn)較為復(fù)雜的bean加載解析。

技術(shù)要點(diǎn):

  • XML诉植、DTD祥国、XSD

什么是XML(EXtensible Markup Language)?

  • XML 指可擴(kuò)展標(biāo)記語(yǔ)言(EXtensible Markup Language)
  • XML 是一種標(biāo)記語(yǔ)言晾腔,很類(lèi)似 HTML
  • XML 的設(shè)計(jì)宗旨是傳輸數(shù)據(jù)舌稀,而非顯示數(shù)據(jù)
  • XML 標(biāo)簽沒(méi)有被預(yù)定義啊犬。您需要自行定義標(biāo)簽。
  • XML 被設(shè)計(jì)為具有自我描述性壁查。
  • XML 是 W3C 的推薦標(biāo)準(zhǔn)

什么是DTD(Document Type Definition)椒惨?

  • 文檔類(lèi)型定義(DTD)可定義合法的XML文檔構(gòu)建模塊。它使用一系列合法的元素來(lái)定義文檔的結(jié)構(gòu)潮罪。DTD 可被成行地聲明于 XML 文檔中康谆,也可作為一個(gè)外部引用。

什么是XSD(XML Schema Definition)嫉到?

  • XML Schema 的作用是定義 XML 文檔的合法構(gòu)建模塊沃暗,類(lèi)似 DTD。

XSD是DTD的繼任者

我們認(rèn)為 XML Schema 很快會(huì)在大部分網(wǎng)絡(luò)應(yīng)用程序中取代 DTD何恶。理由如下:

  • XML Schema 可針對(duì)未來(lái)的需求進(jìn)行擴(kuò)展
  • XML Schema 更完善孽锥,功能更強(qiáng)大
  • XML Schema 基于 XML 編寫(xiě)
  • XML Schema 支持?jǐn)?shù)據(jù)類(lèi)型
  • XML Schema 支持命名空間

自定義Spring標(biāo)簽

自定義xsd:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.fpy.org/schema/beans/test"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.fpy.org/schema/beans/test"
            elementFormDefault="qualified">
    <xsd:element name="testBean">
        <xsd:complexType>
            <xsd:attribute name="id" type="xsd:string" use="required" form="unqualified"/>
            <xsd:attribute name="name" type="xsd:string" use="required" form="unqualified"/>
            <xsd:attribute name="age" type="xsd:integer" use="required" form="unqualified"/>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

xmlns:默認(rèn)命名空間,類(lèi)似import
targetNamespace:定義文件內(nèi)標(biāo)簽所屬命名空間细层,類(lèi)似package
elementFormDefault:在XML文檔中使用局部元素時(shí)惜辑,必須使用限定短名作為前綴

定義namespace與handler映射關(guān)系文件:

Spring解析xml文件時(shí),需要根據(jù)節(jié)點(diǎn)所在命名空間對(duì)應(yīng)的處理器來(lái)解析疫赎。Spring默認(rèn)從resources/META-INF/spring.handlers文件獲取映射關(guān)系盛撑。用戶(hù)也可自定義映射文件路徑。

spring.handlers

http\://www.fpy.org/schema/beans/test=com.example.demo.xsd.CustomNamespaceHandler

定義NamespaceHandler捧搞,解析自定義標(biāo)簽

繼承NamespaceHandlerSupport類(lèi)誉己,在init()方法中注冊(cè)自定義標(biāo)簽的解析器窖张,如testBean標(biāo)簽使用TestBeanDefinitionParser進(jìn)行解析。

TestBeanDefinitionParser實(shí)現(xiàn)BeanDefinitionParser接口,在parse()方法中添加自定義解析規(guī)則坪蚁,并注冊(cè)beanDefinition

public class CustomNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        // 注冊(cè)標(biāo)簽parser
        registerBeanDefinitionParser("testBean", new TestBeanDefinitionParser());
    }

    private static class TestBeanDefinitionParser implements BeanDefinitionParser {

        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            RootBeanDefinition definition = new RootBeanDefinition();
            definition.setBeanClass(TestBean.class);

            MutablePropertyValues mpvs = new MutablePropertyValues();
            mpvs.add("name", element.getAttribute("name"));
            mpvs.add("age", element.getAttribute("age"));
            definition.setPropertyValues(mpvs);

            parserContext.getRegistry().registerBeanDefinition(element.getAttribute("id"), definition);
            return null;
        }
    }
}

定義自定義標(biāo)簽xsd映射路徑

xml文件xsi:schemaLocation定義了命名空間對(duì)應(yīng)的xsd路徑晨缴,當(dāng)改路徑為http文檔時(shí)灸拍,避免因網(wǎng)絡(luò)問(wèn)題導(dǎo)致加載失敗崇堵,我們可在本地定義namespace和xsd的映射關(guān)系。Spring默認(rèn)從resources/META-INF/spring.schemas文件獲取映射關(guān)系爵憎。用戶(hù)也可自定義映射文件路徑慨亲。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:test="http://www.fpy.org/schema/beans/test"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.fpy.org/schema/beans/test http://www.fpy.org/schema/custom_namespace/CustomNamespaceHandlerTests.xsd"
       default-lazy-init="true">
    <test:testBean id="testBean" name="fengpingyu" age="28"/>
</beans>

http://www.fpy.org/schema/custom_namespace/CustomNamespaceHandlerTests.xsd映射到本地文件

spring.schemas

http\://www.fpy.org/schema/custom_namespace/CustomNamespaceHandlerTests.xsd=custom_namespace/CustomNamespaceHandlerTests.xsd

測(cè)試方法

public class CustomNsTests {

    // namespace和handler映射關(guān)系文件
    private static final String NS_PROPS = "custom_namespace/CustomNamespaceHandlerTests.properties";
    // 測(cè)試xml文件
    private static final String NS_XML = "custom_namespace/CustomNamespaceHandlerTests-context.xml";
    // xml的xsd文件
    private static final String TEST_XSD = "custom_namespace/CustomNamespaceHandlerTests.xsd";

    @Test
    public void testCustomNamespaceHandler() {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        NamespaceHandlerResolver nhr = new DefaultNamespaceHandlerResolver(CustomNsTests.class.getClassLoader(), NS_PROPS);
        XmlBeanDefinitionReader bd = new XmlBeanDefinitionReader(factory);
        bd.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
        // 自定義handlers文件路徑
        bd.setNamespaceHandlerResolver(nhr);
        // 自定義schemas文件路徑
        bd.setEntityResolver(new DummySchemaResolver());
        bd.loadBeanDefinitions(NS_XML);
        TestBean testBean = (TestBean) factory.getBean("testBean");
        System.out.println(JSONObject.toJSONString(testBean));
    }

    /**
     * 自定義schemas路徑解析器
     * 默認(rèn)從META-INF/spring.schemas文件讀取,讀取不到時(shí)就自定義路徑讀取
     */
    private final class DummySchemaResolver extends PluggableSchemaResolver {

        public DummySchemaResolver() {
            super(CustomNsTests.class.getClassLoader());
        }

        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws IOException {
            InputSource source = super.resolveEntity(publicId, systemId);
            if (source == null) {
                Resource resource = new ClassPathResource(TEST_XSD);
                source = new InputSource(resource.getInputStream());
                source.setPublicId(publicId);
                source.setSystemId(systemId);
            }
            return source;
        }
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纲堵,一起剝皮案震驚了整個(gè)濱河市巡雨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌席函,老刑警劉巖铐望,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡正蛙,警方通過(guò)查閱死者的電腦和手機(jī)督弓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乒验,“玉大人愚隧,你說(shuō)我怎么就攤上這事《腿” “怎么了狂塘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)鳄厌。 經(jīng)常有香客問(wèn)我荞胡,道長(zhǎng),這世上最難降的妖魔是什么了嚎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任泪漂,我火速辦了婚禮,結(jié)果婚禮上歪泳,老公的妹妹穿的比我還像新娘萝勤。我一直安慰自己,他們只是感情好呐伞,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布敌卓。 她就那樣靜靜地躺著,像睡著了一般荸哟。 火紅的嫁衣襯著肌膚如雪假哎。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,785評(píng)論 1 314
  • 那天鞍历,我揣著相機(jī)與錄音,去河邊找鬼肪虎。 笑死劣砍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扇救。 我是一名探鬼主播刑枝,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼迅腔!你這毒婦竟也來(lái)了装畅?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沧烈,失蹤者是張志新(化名)和其女友劉穎掠兄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚂夕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年迅诬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婿牍。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡侈贷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出等脂,到底是詐尸還是另有隱情俏蛮,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布上遥,位于F島的核電站嫁蛇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏露该。R本人自食惡果不足惜睬棚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望解幼。 院中可真熱鬧抑党,春花似錦、人聲如沸撵摆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)特铝。三九已至暑中,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鲫剿,已是汗流浹背鳄逾。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灵莲,地道東北人雕凹。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像政冻,于是被迫代替她去往敵國(guó)和親枚抵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容