spring源碼學習之:xml配置文件標簽自定義


Spring框架從2.0版本開始,提供了基於Schema風格的XML擴展機制,允許開發者擴展最基本的spring配置文件(一 般是classpath下的spring.xml)。試想一下,如果我們直接在spring.xml中加入一個自定義標簽<mytag id="aty"></matag>,會發生什么呢?spring框架啟動的時候會報錯,因為spring根本不認識我們自定義的& lt;mytag>,這樣對spring.xml的校驗就會失敗,最終結果就是框架不能啟動。有什么方法,能夠讓spring認識並加載解析我們自 定義的<mytag>呢?這就是spring提供的xml擴展機制。我們可以在spring.xml中加入自己的標簽,之后spring會幫 我們解析並納入自己的管理范圍內,這也就是說我們擴展了spring的功能。

現在我們來看下怎么實現這個功能,可以參考spring幫助文檔中的extensible-xml.html。我們知道如果在需要在spring.xml中配置數據源,需要進行如下的配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3309/sampledb" /> <property name="username" value="root" /> <property name="password" value="1234" /> </bean>

這種方式配置雖然也比較簡單,但是有一個缺點:使用<property>標簽不夠明顯,不如元素屬性那么直接。現在我們希望在spring.xml中做如下的配置,就能夠完成數據源的配置。

<aty:datasource id="myDataSourcce" url="jdbc:mysql://localhost:3309/demodb" userName="root" password="root" />

這種方式比較直接,配置不容易出錯。如果讓spring能夠解析這個標簽,需要4步。

1、提供一個xsd文件,負責對xml的標簽<datasource>進行校驗

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.aty.com/schema/aty" xmlns:xsd="http://www.w3.org/2001/XMLSchema"  xmlns:beans="http://www.springframework.org/schema/beans"  targetNamespace="http://www.aty.com/schema/aty" elementFormDefault="qualified"  attributeFormDefault="unqualified">  <xsd:import namespace="http://www.springframework.org/schema/beans" />  <xsd:element name="datasource">   <xsd:complexType>    <xsd:complexContent>     <xsd:extension base="beans:identifiedType">      <xsd:attribute name="url" type="xsd:string" use="required" />      <xsd:attribute name="userName" type="xsd:string" use="required" />      <xsd:attribute name="password" type="xsd:string" use="required" />     </xsd:extension>    </xsd:complexContent>   </xsd:complexType>  </xsd:element> </xsd:schema>

2、定義一個BeanDefinitionParser負責解析xml,並將必要的信息放入spring中

package net.aty.custom.define;

import net.aty.custom.cfg.DataSourceInfo; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; public class DatasourceBeanDefinitionParser implements BeanDefinitionParser {  public BeanDefinition parse(Element element, ParserContext context)  {   RootBeanDefinition def = new RootBeanDefinition();   // 設置Bean Class   def.setBeanClass(DataSourceInfo.class);   // 注冊ID屬性   String id = element.getAttribute("id");   BeanDefinitionHolder idHolder = new BeanDefinitionHolder(def, id);   BeanDefinitionReaderUtils.registerBeanDefinition(idHolder,     context.getRegistry());   // 注冊屬性   String url = element.getAttribute("url");   String userName = element.getAttribute("userName");   String password = element.getAttribute("password");   BeanDefinitionHolder urlHolder = new BeanDefinitionHolder(def, url);   BeanDefinitionHolder userNameHolder = new BeanDefinitionHolder(def,     userName);   BeanDefinitionHolder passwordHolder = new BeanDefinitionHolder(def,     password);   BeanDefinitionReaderUtils.registerBeanDefinition(urlHolder,     context.getRegistry());   BeanDefinitionReaderUtils.registerBeanDefinition(userNameHolder,     context.getRegistry());   BeanDefinitionReaderUtils.registerBeanDefinition(passwordHolder,     context.getRegistry());   def.getPropertyValues().addPropertyValue("url", url);   def.getPropertyValues().addPropertyValue("userName", userName);   def.getPropertyValues().addPropertyValue("password", password);   return def;  } }

該類的功能:設置相關的BeanClass,解析了對應的xsd文件,並將解析的內容注冊到上下文中,同時返回一個BeanDefinition對象 (BeanDefinition是Spring的bean定義,提供了bean部分的操作方法,如isSingleton()、isLazyInit() 等)。注意:id屬性是一個默認的屬性,可以不在xsd文件中描述,但是需要注冊它,否則將無法通過getBean方法獲取標簽定義的bean,也無法被 其他bean引用。


3、定義個NamespaceHandler,由sping框架的調用入口。這也是我們自定義xml解析的入口

package net.aty.custom.define;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class DatasourceNamespaceHandlerSupport extends NamespaceHandlerSupport {  @Override  public void init()  {   registerBeanDefinitionParser("datasource",     new DatasourceBeanDefinitionParser());  } }

4、配置schema和handler

Spring沒那么聰明,它無法知道我們在什么地方定義了哪些擴展標簽,這些標簽將被誰解析,怎么解析。這個過程要我們通過一些配置 文件來告知Spring知道,它們就是spring.handlers和spring.schemas,它們放在META-INF目錄中。 Spring.jar的META-INF目錄中也有同名的文件,它們的文件內容基本上是相似的,而Spring在執行過程中,如果發現其他jar文件的 META-INF文件夾中包含有這兩個文件,Spring將會合並它們。

spring.handlers內容如下:

http\://www.aty.com/schema/aty=net.aty.custom.define.DatasourceNamespaceHandlerSupport

spring.schemas內容如下:

http\://www.aty.com/schema/aty.xsd=aty.xsd

我的工程目錄結構如下圖:

測試工程的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:aty="http://www.aty.com/schema/aty"  xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  http://www.aty.com/schema/aty  http://www.aty.com/schema/aty.xsd">  <aty:datasource id="myDataSourcce" url="jdbc:mysql://localhost:3309/demodb" userName="root" password="root" /> </beans>

測試類代碼如下:

import net.aty.custom.cfg.DataSourceInfo;

import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestMain {  private static ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(    "spring.xml");  public static void main(String[] args)  {   DataSourceInfo d = (DataSourceInfo) context.getBean("myDataSourcce");   System.out.println(d);  } }

測試的工程目錄結構如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM