Spring XML Schema擴展機制的使用示例
前言
在當前Java生態,Spring算的上是最核心的框架,所有的開發組件想要得到大范圍更便捷的使用,都要和Spring進行整合,比如我們熟知的Mybatis、Dubbo等,以及內部封裝的各類組件包括Redis、MQ、配置中心等。
有瞭整合這一步,我們隻需引入相應的jar,比如mybatis-spring,然後進行簡單的配置後即可在Spring工程中使用Mybatis的功能,也正是由於這樣的便捷性,導致很多時候我們沒有對其進行深究。
XML Schema擴展
打開mybatis-spring、dubbo的源碼會發現在META-INF目錄下有兩個文件(如下圖所示),spring.handlers與spring.schemas,這兩個文件就是XML Schema擴展的關鍵入口點。
XSD
XSD,XML Schema Definition,XML定義。
XML Schema定義XML文檔的結構,XML Schema語言也稱為XML定義,即XSD。
簡單的說,XSD用於制定xml文件規范,包括xml中的元素(簡單元素、復雜元素)、屬性、以及屬性類型及約束等。
Spring XML Schema擴展的第一步就是要定義一個xsd文件,比如spring-beans對應xsd文件為http://www.springframework.org/schema/beans/spring-beans.xsd,如下圖:
為瞭簡單介紹Spring XML Schema擴展實現,下面將一個簡單例子(模擬一個簡單的分佈式id生成器,不會實現具體功能)進行說明,xsd定義如下(文件命名為DistributedId.xsd,在META-INF目錄下):
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.hexup.com/schema/distributed-id" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.hexup.com/schema/distributed-id"> <xsd:element name="distributed-id"> <xsd:complexType> <xsd:attribute name="id" type="xsd:string"></xsd:attribute> <xsd:attribute name="bizCode" type="xsd:string"></xsd:attribute> <xsd:attribute name="length" type="xsd:int"></xsd:attribute> </xsd:complexType> </xsd:element> </xsd:schema>
上述xsd文件裡定義瞭一個復雜元素distributed-id,包含屬性id,bizCode,length,形如:
<distributed-id id="xxx" bizCode="xxx" length="xxx"></distributed-id>
註意:xmlns,即為xml namespace,xml命名空間,後面跟的http鏈接地址可以不存在,因為xsd會放在當前工程的META-INF下。
配置spring.handlers和spring.schemas
如下兩張圖所示,spring.schemas文件中用於說明xsd的文件路徑,spring.schemas文件用於說明解析此類xsd定義的標簽的處理類,下面會對處理類進行詳細說明。
NameSpaceHandler與BeanDefinitionParser
定義類DistributedIdNamespaceHandler繼承NamespaceHandlerSupport,init方法用於註冊BeanDefinition解析器,也就是解析xml中對應標簽為Spring Bean。
public class DistributedIdNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("distributed-id", new DistributedIdParser()); } }
同時要創建BeanDefinitionParser
public class DistributedIdParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { // 解析xml內的標簽 String bizCode = element.getAttribute("bizCode"); int length = Integer.valueOf(element.getAttribute("length")); String id = element.getAttribute("id"); // 創建DistributedIdFactoryBean bean BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); builder.getRawBeanDefinition().setBeanClass(DistributedIdFactoryBean.class); builder.setScope(BeanDefinition.SCOPE_SINGLETON); builder.addPropertyValue("bizCode", bizCode); builder.addPropertyValue("length", length); BeanDefinition beanDefinition = builder.getBeanDefinition(); parserContext.getRegistry().registerBeanDefinition(id, beanDefinition); return beanDefinition; } }
其中DistributedIdFactoryBean實現FactoryBean接口用於創建DistributedIdComponent Bean,如下
public class DistributedIdFactoryBean implements InitializingBean, FactoryBean<DistributedIdComponent> { private String bizCode; private int length; private DistributedIdComponent distributedIdComponent; @Override public DistributedIdComponent getObject() throws Exception { return distributedIdComponent; } @Override public Class<?> getObjectType() { return DistributedIdComponent.class; } @Override public boolean isSingleton() { return false; } @Override public void afterPropertiesSet() throws Exception { distributedIdComponent = new DistributedIdComponent(bizCode, length); } public void setBizCode(String bizCode) { this.bizCode = bizCode; } public void setLength(int length) { this.length = length; } }
目標Bean DistributedIdComponent如下:
public class DistributedIdComponent { private String bizCode; private int length; public DistributedIdComponent() { } public DistributedIdComponent(String bizCode, int length) { this.bizCode = bizCode; this.length = length; } public String generateId() { System.out.println("mock generate id"); return String.valueOf(System.currentTimeMillis()).substring(0, length); } public String getBizCode() { return bizCode; } public void setBizCode(String bizCode) { this.bizCode = bizCode; } public int getLength() { return length; } public void setLength(int length) { this.length = length; } }
使用
spring配置文件,spring-service.xml中配置distributed-id標簽以及對應的屬性值,如下:
<?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:distributed-id="http://www.hexup.com/schema/distributed-id" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.hexup.com/schema/distributed-id http://www.hexup.com/schema/distributed-id.xsd"> <distributed-id:distributed-id id="test" bizCode="test" length="8"></distributed-id:distributed-id> </beans>
運行容器驗證:
public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-service.xml"); DistributedIdComponent bean = context.getBean(DistributedIdComponent.class); String id = bean.generateId(); System.out.println("id:" + id); } }
總結
本文主要介紹瞭Spring XML Schema擴展機制的使用方法,大致步驟為定義XSD文件、配置spring.schemas、編碼實現NameSpaceHanlder和BeanDefinitionParser實現類、配置spring.handlers。但未說明具體的實現原理,後續會有一篇文章詳細介紹Spring源碼是怎麼實現擴展的,以及介紹為什麼使用FactoryBean來創建具體的Bean等問題。
以上就是Spring XML Schema擴展機制的使用示例的詳細內容,更多關於Spring XML Schema擴展機制的使用的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 如何使用Spring自定義Xml標簽
- Spring P標簽的使用詳解
- Spring IOC容器FactoryBean工廠Bean實例
- Spring 控制反轉和依賴註入的具體使用
- Spring概述和快速構建的方式