Spring框架是現在Java最流行的開源框架之一,并且Spring下的各種子項目對某些特定問題的解決有很好的支持。因此,如果能在Spring 基礎上實現搭建自己的一套框架(基于XML配置)。就必然需要實現一些自定義的標簽,主要是方便使用我們框架的人能夠快速、簡單進行配置。
1. XML Schema
要想自定義標簽,首先第一步需要寫自己的XML Schema。XML Schema的個人感覺比較復雜,網上的教程比較簡單,因此可以參照spring-beans.xsd依葫蘆畫瓢。這里就按照我自己的理解進行簡單介紹一下吧。
1.1 最簡單的標簽
一個最簡單的標簽,形式如:
1
|
< bf:head-routing key = "1" value = "1" to = "test2" /> |
該標簽只包含了若干屬性,我們就在xsd文件中這么定義
1
2
3
4
5
6
7
8
9
10
|
<!-- 聲明一個標簽,名字為head-routing,他的類型為headRouting--> < xsd:element name = "head-routing" type = "headRouting" ></ xsd:element > <!-- 定義head-routing的類型,這里定義它有key,value,to,patten四個屬性 --> < xsd:complexType name = "headRouting" > < xsd:attribute name = "key" type = "xsd:string" use = "required" ></ xsd:attribute > < xsd:attribute name = "value" type = "xsd:string" use = "required" ></ xsd:attribute > < xsd:attribute name = "to" type = "xsd:IDREF" use = "required" ></ xsd:attribute > < xsd:attribute name = "patten" type = "xsd:string" default = "string" ></ xsd:attribute > </ xsd:complexType > |
在<xsd:attribute>標簽中的type是用來定義該屬性的格式,例如
-
xsd:string 表示是一個字符串,對格式沒什么要求
-
xsd:id 表示該屬性的值是一個id,有格式要求(例如不能以數字開頭)。
-
xsd:IDREF 表示該屬性的值與某xsd:id屬性的值對應
-
其他還有很多,例如number,double,datetime等等。
1.2 復雜點的標簽
所謂復雜,其實就是嵌套的標簽,形式如:
1
2
3
|
< bf:stop id = "test1" ref = "testNode" > < bf:head-routing key = "1" value = "1" to = "test2" /> </ bf:stop > |
其實只要參照Spring 中<bean>標簽的xsd依葫蘆畫瓢,首先是定義stop標簽
1
2
3
4
5
6
7
8
9
10
|
< xsd:element name = "stop" > < xsd:complexType > < xsd:complexContent > < xsd:extension base = "beans:identifiedType" > < xsd:group ref = "stopElements" /> < xsd:attributeGroup ref = "stopAttributes" /> </ xsd:extension > </ xsd:complexContent > </ xsd:complexType > </ xsd:element > |
其中,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
< xsd:extension base = "beans:identifiedType" > 定義了該標簽的id屬性,注意這里引用的是spring-beans中的type, < xsd:group ref = "stopElements" />中定義了< bf:stop >標簽允許的子標簽 < xsd:attributeGroup ref = "stopAttributes" /> 定義了< bf:stop >標簽允許的屬性 < xsd:group name = "stopElements" > < xsd:sequence > < xsd:element ref = "description" minOccurs = "0" /> < xsd:choice minOccurs = "0" maxOccurs = "unbounded" > < xsd:element ref = "head-routing" /> <!-- 有更多的子標簽繼續在這里添加,例如<xsd:element ref="properties"/> --> </ xsd:choice > </ xsd:sequence > </ xsd:group > < xsd:attributeGroup name = "stopAttributes" > < xsd:attribute name = "ref" type = "xsd:IDREF" use = "required" > < xsd:annotation > < xsd:appinfo > <!-- 這里是使用了Spring tool xsd中的標簽,格式校驗--> < tool:annotation kind = "ref" > < tool:expected-type type = "com.lizo.node.Station" /> </ tool:annotation > </ xsd:appinfo > </ xsd:annotation > </ xsd:attribute > <!-- 有更多的子標簽繼續在這里添加,例如<xsd:attribute name="value" type="xsd:string"/> --> |
2. 配置文件
完成了xsd文件編寫后,還需要讓該文件生效,就需要在項目的resource/META-INF包里面配置2個文件spring.handlers和spring.schemas
2.1 spring.schemas
改配置文件主要是用一個url來映射我們第一步配置好的文件,形式如下
http\://www.lizo.com/schema/bf.xsd=META-INF/bf.xsd
這樣,就可以在Spring的xml配置文件中加入spring.schemas的url,省略掉其他的,在<beans>標簽中增加如下信息
1
2
3
4
5
6
7
8
|
< beans .. xmlns:bf = "http://www.lizo.com/schema/bf" xsi:schemaLocation=" ... http://www.lizo.com/schema/bf http://www.lizo.com/schema/bf.xsd "> |
完成這步以后,就可以在xml中寫自己的標簽了,例如自定義標簽的namespace為bf,
1
2
3
4
|
< bf:stop id = "test123" ref = "testNode" > < bf:head-routing key = "1" value = "1" to = "test1" /> < bf:head-routing key = "3" value = "4" to = "test2" /> </ bf:stop > |
2.2 spring.handlers
這個配置文件用來配置解析我們bf標簽,然后生成一些BeanDefinition進行注冊。例如
http\://www.lizo.com/schema/bf=com.lizo.config.BusinessFlowNamespaceHandlerSupport
其中 BusinessFlowNamespaceHandlerSupport就是我們用來解析標簽
3. 自定義標簽解析
在上一步中,我們配置了com.lizo.config.BusinessFlowNamespaceHandlerSupport類作為解析自定義標簽的類,所以namespace為bf的標簽,都會用這里注冊的標簽解析器來解析
1
2
3
4
5
6
|
public class BusinessFlowNamespaceHandlerSupport extends NamespaceHandlerSupport { public void init() { //注冊用于解析<bf:stop>的解析器 registerBeanDefinitionParser( "stop" , new BusinessFlowBeanDefinitionParser()); } } |
我們自定義的標簽解析器BusinessFlowBeanDefinitionParser是要實現BeanDefinitionParser 接口的
1
2
3
|
public interface BeanDefinitionParser { BeanDefinition parse(Element element, ParserContext parserContext); } |
一般來說,注冊bean的基本流程為:
-
解析標簽
-
根據解析的值生成BeanDefinition,
-
注冊標簽
解析標簽就不用說,重點說說怎么生成BeanDefinition
3.1 生成BeanDefinition
一個最簡單的BeanDefinition通過設置Class和屬性的注入就可以完成。如下:
1
2
3
4
5
|
RootBeanDefinition nodeWrapDefinition = new RootBeanDefinition(); //該BeanDefinition對應的是什么類 nodeWrapDefinition.setBeanClass(StationRoutingWrap. class ); //name是解析標簽后獲得的值 nodeWrapDefinition.getPropertyValues().addPropertyValue( "name" , name); |
RuntimeBeanReference
RuntimeBeanReference 用于在運行時去獲取BeanDefinition,因為在我們創建這個BeanDefinition的時候我們只知道他的beanName,并不確定是否已經注冊了,這個時候就需要用RuntimeBeanReference,例如
1
2
|
RuntimeBeanReference refBean = new RuntimeBeanReference(ref); nodeWrapDefinition.getPropertyValues().addPropertyValue( "station" , refBean); |
集合類BeanDefinition
某個BeanDefinition注入的屬性為一個List,這個時候就需要用ManagedList(同理有ManagedMap,ManagedSet),
1
2
3
|
ManagedList routingConditions = new ManagedList(); .... nodeWrapDefinition.getPropertyValues().add( "routing" , routing); |
3.2 注冊bean
注冊BeanDefinitionParser 接口的函數中有個參數ParserContext,有個方法為getRegistry(),因此,注冊bean的時候就很簡單了
parserContext.getRegistry().registerBeanDefinition("beanName",nodeWrapDefinition);
總結
通過以上三步,就可以實現自己定義標簽,并且在Spring容器中注入相關的bean。讓我們的框架使用起來更方便
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://my.oschina.net/u/3039671/blog/875325