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