在 Dubbo 中,可使用 XML 配置相關信息,也能夠用來引入服務或者導出服務。配置完成,啓動工程,Spring 會讀取配置文件,生成注入 相關 Bean。那 Dubbo 如何實現自定義 XML 被 Spring 加載讀取?html
Spring XML Schema 擴展機制。從 Spring 2.0 開始,Spring 開始提供了一種基於 XML Schema 格式擴展機制,用於定義和配置 bean。java
實現 Spring XML Schema 擴展,其實很是簡單,只須要完成下面四步。spring
BeanDefinitionParser
。NamespaceHandler
實現類。NamespaceHandler
以及 XSD 文件。咱們按照以上步驟,最終完整 Spring 解析以下配置。緩存
<?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:demo="http://www.test.com/demo" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.test.com/demo http://www.test.com/demo/demo.xsd"> <demo:application name="test" id="test"/> </beans>
XSD 文件,主要用來定義 XML 格式,用來驗證 XML 合法性。在 IDE 中,導入 XSD 文件,編輯 XML 文件能夠得到相關提示。app
下面咱們生成一個 XSD 文件。ide
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.test.com/demo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.test.com/demo" elementFormDefault="qualified" attributeFormDefault="unqualified"> <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:schema>
上面 XSD 文件中 http://www.test.com/demo 爲自定義命名空間地址,下面將會使用到。測試
這裏實現 BeanDefinitionParser,真正解析 XML 動做在這裏完成。ui
因爲上面的例子比較簡單,咱們能夠直接繼承 Spring 提供的抽象類 AbstractSingleBeanDefinitionParser
,而後實現相關方法就能夠了。spa
public class DemoBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { /** * 返回最會須要注入 Spring Bean 的類型 * @param element * @return */ @Override protected Class<?> getBeanClass(Element element) { return DemoApplication.class; } /*** * 這個方法完成真正解析動做 * @param element * @param builder */ @Override protected void doParse(Element element, BeanDefinitionBuilder builder) { String name=element.getAttribute("name"); builder.addPropertyValue("name",name); } }
固然也能夠直接實現 BeanDefinitionParser,這樣更加靈活,可是這樣相比於上面這個就比較複雜了。code
public class BeanApplicationDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { String name=element.getAttribute("name"); // Bean 定義,最後根據這個生產 Bean RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(); rootBeanDefinition.setBeanClass(DemoApplication.class); rootBeanDefinition.setLazyInit(false); // 添加解析的屬性 rootBeanDefinition.getPropertyValues().add("name",name); // 將生成的 BeanDefinition 註冊,少了這一步將會致使最後生成 Bean 時報錯 parserContext.getRegistry().registerBeanDefinition("application",rootBeanDefinition); return rootBeanDefinition; } }
這一步實現 NamespaceHandler,開發者自定義 NamespaceHandler 只要繼承 NamespaceHandlerSupport
抽象類,實現 init
方法。在這個方法中註冊上面一步實現 BeanDefinitionParser
。
public class DemoNameSpaceHandler extends NamespaceHandlerSupport { @Override public void init() { // elementName 爲命名空間 registerBeanDefinitionParser("application",new BeanApplicationDefinitionParser()); } }
這一步咱們須要在 META-INF 中生成兩個配置文件,分別爲 spring.handlers
,spring.schemas
。
spring.schemas
指定 XSD 文件路徑。
http\://www.test.com/demo/demo.xsd=com/spring/learning/xml/schemas/autoring/leanrn/demo.xsd
spring.handlers
指定 NamespaceHandler
完整類名,既包含前面的包名。
這裏須要注意的是
:
須要進行轉義
首先咱們生產 Spring 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:demo="http://www.test.com/demo" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.test.com/demo http://www.test.com/demo/demo.xsd"> <demo:application name="test" id="test"/> </beans>
這裏須要注意須要使用 XSD 文件中定義 http://www.test.com/demo
。
接着咱們使用 SpringBoot ,導入 XML 文件,而後運行。
@SpringBootApplication @ImportResource(locations = {"classpath:applicationContext.xml"}) public class XmlSchemaApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(XmlSchemaApplication.class, args); DemoApplication demoApplication=applicationContext.getBean(DemoApplication.class); System.out.println("application name is "+demoApplication.getName()); } }
輸出結果爲:
application name is test
這裏咱們主要研究自定義 XML 擴展文件如何被 Spring 加載。
Spring 啓動過程當中會經過 BeanDefinitionDocumentReader
讀取 beans 標籤裏面全部配置,這個過程將會經過 BeanDefinitionParserDelegate#parseCustomElement
解析自定義元素。
上面解析過程能夠得到自定義 NamespaceHandler
,而後調用 parse
方法解析。
接着咱們查看 NamespaceHandlerResolver#resolve
方法,查看如何獲取自定義 NamespaceHandler
。
在這個方法中,主要是從 handlerMappings
緩存中獲取 NamespaceHandler
。而該緩存來源於 getHandlerMappings
方法,這個方法將會加載咱們上面自定義 spring.handlers
文件。
看完 Spring 加載 NamespaceHandler
過程,下面咱們查看最重要 BeanDefinition
如何生成。
上面已經講到 Spring 會使用 NamespaceHandler.parse
解析,因爲咱們繼承了 NamespaceHandlerSupport
,查看裏面具體實現。
獲取到 BeanDefinition 會將其註冊到容器中,而後會經過 BeanDefinition
生成 Bean。這個生成過程不屬於本章節內容,因此再也不概述,感興趣同窗能夠自行搜索。
最後咱們查看 Dubbo XML Schema 擴展如何實現。
能夠看到 Dubbo XML Schema 擴展恰好對應 Spring 四個標準的步驟。
最後用一張圖片總結全文內容。