最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring中XML schema擴展機制的深入講解

 更新時間:2018年09月04日 09:37:29   作者:徐靖峰  
這篇文章主要給大家介紹了關(guān)于Spring中XML schema擴展機制的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

很久沒有寫關(guān)于 Spring 的文章了,最近在系統(tǒng)梳理 Dubbo 代碼的過程中發(fā)現(xiàn)了 XML schema 這個被遺漏的知識點。由于工作中使用 SpringBoot 比較多的原因,幾乎很少接觸 XML,此文可以算做是亡羊補牢,另一方面,也為后續(xù)的 Dubbo 源碼解析做個鋪墊。

XML schema 擴展機制是啥?從Spring2.0開始,Spring提供了XML Schema可擴展機制,用戶可以自定義XML Schema文件,并自定義XML Bean解析器,并集成到Spring Ioc 容器中。這并不是一塊很大的知識點,翻閱一下 Spring 的文檔,我甚至沒找到一個貫穿上下文的詞來描述這個功能,XML Schema Authoring 是文檔中對應的標題,簡單來說:

Spring 為基于 XML 構(gòu)建的應用提供了一種擴展機制,用于定義和配置 Bean。 它允許使用者編寫自定義的 XML bean 解析器,并將解析器本身以及最終定義的 Bean 集成到 Spring IOC 容器中。

Dubbo 依賴了 Spring,并提供了一套自定義的 XML 標簽,<dubbo:application> ,<dubbo:registry> ,<dubbo:protocol>,<dubbo:service>。作為使用者,大多數(shù)人只需要關(guān)心這些參數(shù)如何配置,但不知道有沒有人好奇過,它們是如何加載進入 Spring 的 IOC 容器中被其他組件使用的呢?這便牽扯出了今天的主題:Spring 對 XML schema 的擴展支持。

自定義 XML 擴展

為了搞懂 Spring 的 XML 擴展機制,最直接的方式便是實現(xiàn)一個自定義的擴展。實現(xiàn)的步驟也非常簡單,分為四步:

  • 編寫一個 XML schema 文件描述的你節(jié)點元素。
  • 編寫一個 NamespaceHandler 的實現(xiàn)類
  • 編寫一個或者多個 BeanDefinitionParser 的實現(xiàn) (關(guān)鍵步驟).
  • 注冊上述的 schema 和 handler。

我們的目的便是想要實現(xiàn)一個 kirito XML schema,我們的項目中可以自定義 kirito.xml,在其中會以 kirito 為標簽來定義不同的類,并在最終的測試代碼中驗證這些聲明在 kirito.xml 的類是否被 Spring 成功加載。大概像這樣,是不是和 dubbo.xml 的格式很像呢?

動手實現(xiàn)

有了明確的目標,我們逐步開展自己的工作。

1 編寫kirito.xsd

resources/META-INF/kirito.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.cnkirito.moe/schema/kirito"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:beans="http://www.springframework.org/schema/beans"
   targetNamespace="http://www.cnkirito.moe/schema/kirito"> ①

 <xsd:import namespace="http://www.springframework.org/schema/beans"/>

 <xsd:element name="application"> ②
  <xsd:complexType>
   <xsd:complexContent>
    <xsd:extension base="beans:identifiedType">
     <xsd:attribute name="name" type="xsd:string" use="required"/>
    </xsd:extension>
   </xsd:complexContent>
  </xsd:complexType>
 </xsd:element>

 <xsd:element name="service"> ②
  <xsd:complexType>
   <xsd:complexContent>
    <xsd:extension base="beans:identifiedType">
     <xsd:attribute name="name" type="xsd:string" use="required"/>
    </xsd:extension>
   </xsd:complexContent>
  </xsd:complexType>
 </xsd:element>


</xsd:schema>

① 注意這里的 targetNamespace="http://www.cnkirito.moe/schema/kirito" 這便是之后 kirito 標簽的關(guān)鍵點。

② kirito.xsd 定義了兩個元素: application 和 service,出于簡單考慮,都只有一個 name 字段。

schema 的意義在于它可以和 eclipse/IDEA 這樣智能化的集成開發(fā)環(huán)境形成很好的搭配,在編輯 XML 的過程中,用戶可以獲得告警和提示。 如果配置得當,可以使用自動完成功能讓用戶在事先定義好的枚舉類型中進行選擇。

2 編寫KiritoNamespaceHandler

public class KiritoNamespaceHandler extends NamespaceHandlerSupport {

 @Override
 public void init() {
  super.registerBeanDefinitionParser("application", new KiritoBeanDefinitionParser(ApplicationConfig.class));
  super.registerBeanDefinitionParser("service", new KiritoBeanDefinitionParser(ServiceBean.class));
 }
}

完成 schema 之后,還需要一個 NamespaceHandler 來幫助 Spring 解析 XML 中不同命名空間的各類元素。

<kirito:application name="kirito"/>
<dubbo:application name="dubbo"/>
<motan:application name="motan"/>

不同的命名空間需要不同的 NamespaceHandler 來處理,在今天的示例中,我們使用 KiritoNamespaceHandler 來解析 kirito 命名空間。KiritoNamespaceHandler 繼承自 NamespaceHandlerSupport 類,并在其 init() 方法中注冊了兩個 BeanDefinitionParser ,用于解析 kirito 命名空間/kirito.xsd 約束中定義的兩個元素:application,service。BeanDefinitionParser 是下一步的主角,我們暫且跳過,將重心放在父類 NamespaceHandlerSupport 之上。

public interface NamespaceHandler {
 void init();
 BeanDefinition parse(Element element, ParserContext parserContext);
 BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
}

NamespaceHandlerSupport 是 NamespaceHandler 命名空間處理器的抽象實現(xiàn),我粗略看了NamespaceHandler 的幾個實現(xiàn)類,parse 和 decorate 方法可以完成元素節(jié)點的組裝并通過 ParserContext 注冊到 Ioc 容器中,但實際我們并沒有調(diào)用這兩個方法,而是通過 init() 方法注冊 BeanDefinitionParser 來完成解析節(jié)點以及注冊 Bean 的工作,所以對于 NamespaceHandler,我們主要關(guān)心 init 中注冊的兩個 BeanDefinitionParser 即可。

3 編寫KiritoBeanDefinitionParser

在文章開始我們便標記到 BeanDefinitionParser 是最為關(guān)鍵的一環(huán),每一個 BeanDefinitionParser 實現(xiàn)類都負責一個映射,將一個 XML 節(jié)點解析成 IOC 容器中的一個實體類。

public class KiritoBeanDefinitionParser implements BeanDefinitionParser {

 private final Class<?> beanClass;

 public KiritoBeanDefinitionParser(Class<?> beanClass) {
  this.beanClass = beanClass;
 }

 private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass) {
  RootBeanDefinition beanDefinition = new RootBeanDefinition();
  beanDefinition.setBeanClass(beanClass);
  beanDefinition.setLazyInit(false);
  String name = element.getAttribute("name");
  beanDefinition.getPropertyValues().addPropertyValue("name", name);
  parserContext.getRegistry().registerBeanDefinition(name, beanDefinition);
  return beanDefinition;
 }

 @Override
 public BeanDefinition parse(Element element, ParserContext parserContext) {
  return parse(element, parserContext, beanClass);
 }
}

由于我們的實體類是非常簡單的,所以不存在很復雜的解析代碼,而實際項目中,往往需要大量的解析步驟。parse 方法會解析一個個 XML 中的元素,使用 RootBeanDefinition 組裝成對象,并最終通過 parserContext 注冊到 IOC 容器中。

至此,我們便完成了 XML 文件中定義的對象到 IOC 容器的映射。

4 注冊schema和handler

最后一步還需要通知 Spring,告知其自定義 schema 的所在之處以及對應的處理器。

resources/META-INF/spring.handlers

http\://www.cnkirito.moe/schema/kirito=moe.cnkirito.sample.xsd.KiritoNamespaceHandler

resources/META-INF/spring.schemas

http\://www.cnkirito.moe/schema/kirito/kirito.xsd=META-INF/kirito.xsd

沒有太多可以說的,需要遵守 Spring 的約定。

至此一個自定義的 XML schema 便擴展完成了,隨后來驗證一下。

驗證擴展

我們首先定義好 kirito.xml

<?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:kirito="http://www.cnkirito.moe/schema/kirito"
  xsi:schemaLocation=" http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.cnkirito.moe/schema/kirito
        http://www.cnkirito.moe/schema/kirito/kirito.xsd">

 <kirito:application name="kirito-demo-application"/>

 <kirito:service name="kirito-demo-service"/>

</beans>

使用 Spring 去加載它,并驗證 IOC 容器中是否存在注冊成功的 Bean。

@SpringBootApplication
@ImportResource(locations = {"classpath:kirito.xml"})
public class XmlSchemaAuthoringSampleApplication {

 public static void main(String[] args) {
  ConfigurableApplicationContext applicationContext = SpringApplication.run(XmlSchemaAuthoringSampleApplication.class, args);
  ServiceBean serviceBean = applicationContext.getBean(ServiceBean.class);
  System.out.println(serviceBean.getName());
  ApplicationConfig applicationConfig = applicationContext.getBean(ApplicationConfig.class);
  System.out.println(applicationConfig.getName());
 }
}

觀察控制臺的輸出:

kirito-demo-service
kirito-demo-application

一個基礎(chǔ)的基于 XML schema 的擴展便完成了。

Dubbo中的XML schema擴展

最后我們以 Dubbo 為例,看看一個成熟的 XML schema 擴展是如何被應用的。

剛好對應了四個標準的擴展步驟,是不是對 XML 配置下的 Dubbo 應用有了更好的理解了呢?

順帶一提,僅僅完成 Bean 的注冊還是不夠的,在“注冊”的同時,Dubbo 還進行了一系列其他操作如:暴露端口,開啟服務器,完成注冊中心的注冊,生成代理對象等等行為,由于不在本文的范圍內(nèi),后續(xù)的 Dubbo 專題會專門介紹這些細節(jié),本文便是了解 Dubbo 加載流程的前置文章了。

總結(jié):

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Spring Boot中單例類實現(xiàn)對象的注入方式

    Spring Boot中單例類實現(xiàn)對象的注入方式

    這篇文章主要介紹了Spring Boot中單例類實現(xiàn)對象的注入方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • MyBatis動態(tài)SQL實現(xiàn)配置過程解析

    MyBatis動態(tài)SQL實現(xiàn)配置過程解析

    這篇文章主要介紹了MyBatis動態(tài)SQL實現(xiàn)配置過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • Java內(nèi)存分配多種情況的用法解析

    Java內(nèi)存分配多種情況的用法解析

    這篇文章主要介紹了Java內(nèi)存分配多種情況的用法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • 利用IDEA工具修改Maven多模塊項目標識包名全過程記錄

    利用IDEA工具修改Maven多模塊項目標識包名全過程記錄

    當我們?yōu)榧追椒仗峁┸浖_發(fā)服務時,需要按照甲方的要求去修改軟件的標識,對于Maven項目來說就對應著groupId,一般地寫對方公司的域名,如com.example,接下來通過本文給大家分享IDEA修改Maven多模塊項目標識包名,感興趣的朋友一起看看吧
    2022-09-09
  • IDEA提示內(nèi)存不足 low memory的完美解決方法(親測好用)

    IDEA提示內(nèi)存不足 low memory的完美解決方法(親測好用)

    這篇文章主要介紹了IDEA提示內(nèi)存不足 low memory的完美解決方法(親測好用),這里以IDEA2022版本為例,在IDE中 幫助(help)–>change memory setting(改變內(nèi)存設置),具體設置辦法文中給大家詳細講解,需要的朋友可以參考下
    2023-01-01
  • SpringBoot前后端分離實現(xiàn)個人博客系統(tǒng)

    SpringBoot前后端分離實現(xiàn)個人博客系統(tǒng)

    這篇文章主要為大家詳細介紹了使用springboot+mybatis+前端vue,使用前后端分離架構(gòu)實現(xiàn)的個人博客系統(tǒng),感興趣的小伙伴可以動手嘗試一下
    2022-06-06
  • java實現(xiàn)列表、集合與數(shù)組之間轉(zhuǎn)化的方法

    java實現(xiàn)列表、集合與數(shù)組之間轉(zhuǎn)化的方法

    這篇文章主要介紹了java實現(xiàn)列表、集合與數(shù)組之間轉(zhuǎn)化的方法,涉及java中列表、集合與數(shù)組相互轉(zhuǎn)換的技巧,非常具有實用價值,需要的朋友可以參考下
    2015-03-03
  • java中的日期和時間比較大小

    java中的日期和時間比較大小

    這篇文章主要介紹了java中的日期和時間比較大小,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • 理解Java面向?qū)ο缶幊淘O計

    理解Java面向?qū)ο缶幊淘O計

    這篇文章主要介紹了理解Java面向?qū)ο缶幊淘O計,面向?qū)ο缶幊淌且环N編程思維方式和編碼架構(gòu)。下面詳細內(nèi)容,需要的小伙伴可以參考一下
    2022-01-01
  • SpringBoot項目啟動后立馬自動關(guān)閉的解決方案

    SpringBoot項目啟動后立馬自動關(guān)閉的解決方案

    這篇文章主要介紹了SpringBoot項目啟動后立馬自動關(guān)閉的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03

最新評論

敦化市| 兴隆县| 宣城市| 开化县| 鹰潭市| 芦溪县| 普洱| 武胜县| 奉新县| 彰武县| 广南县| 敦化市| 醴陵市| 类乌齐县| 宝应县| 鄯善县| 广宁县| 曲沃县| 黄石市| 泸水县| 达拉特旗| 阳春市| 综艺| 大石桥市| 忻城县| 安西县| 吐鲁番市| 崇阳县| 洪江市| 修文县| 中宁县| 弥勒县| 博爱县| 崇仁县| 滕州市| 东源县| 新建县| 海宁市| 醴陵市| 天长市| 康保县|