基于Spring开发之自定义标签及其解析
spring框架是现在java最流行的开源框架之一,并且spring下的各种子项目对某些特定问题的解决有很好的支持。因此,如果能在spring 基础上实现搭建自己的一套框架(基于xml配置)。就必然需要实现一些自定义的标签,主要是方便使用我们框架的人能够快速、简单进行配置。
1. xml schema
要想自定义标签,首先第一步需要写自己的xml schema。xml schema的个人感觉比较复杂,网上的教程比较简单,因此可以参照spring-beans.xsd依葫芦画瓢。这里就按照我自己的理解进行简单介绍一下吧。
1.1 最简单的标签
一个最简单的标签,形式如:
<bf:head-routing key="1" value="1" to="test2"/>
该标签只包含了若干属性,我们就在xsd文件中这么定义
<!-- 声明一个标签,名字为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 复杂点的标签
所谓复杂,其实就是嵌套的标签,形式如:
<bf:stop id="test1" ref="testnode"> <bf:head-routing key="1" value="1" to="test2"/> </bf:stop>
其实只要参照spring 中<bean>标签的xsd依葫芦画瓢,首先是定义stop标签
<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>
其中,
<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>标签中增加如下信息
<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,
<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的标签,都会用这里注册的标签解析器来解析
public class businessflownamespacehandlersupport extends namespacehandlersupport { public void init() { //注册用于解析<bf:stop>的解析器 registerbeandefinitionparser("stop", new businessflowbeandefinitionparser()); } }
我们自定义的标签解析器businessflowbeandefinitionparser是要实现beandefinitionparser 接口的
public interface beandefinitionparser { beandefinition parse(element element, parsercontext parsercontext); }
一般来说,注册bean的基本流程为:
- 解析标签
- 根据解析的值生成beandefinition,
- 注册标签
解析标签就不用说,重点说说怎么生成beandefinition
3.1 生成beandefinition
一个最简单的beandefinition通过设置class和属性的注入就可以完成。如下:
rootbeandefinition nodewrapdefinition = new rootbeandefinition(); //该beandefinition对应的是什么类 nodewrapdefinition.setbeanclass(stationroutingwrap.class); //name是解析标签后获得的值 nodewrapdefinition.getpropertyvalues().addpropertyvalue("name", name);
runtimebeanreference
runtimebeanreference 用于在运行时去获取beandefinition,因为在我们创建这个beandefinition的时候我们只知道他的beanname,并不确定是否已经注册了,这个时候就需要用runtimebeanreference,例如
runtimebeanreference refbean = new runtimebeanreference(ref); nodewrapdefinition.getpropertyvalues().addpropertyvalue("station", refbean);
集合类beandefinition
某个beandefinition注入的属性为一个list,这个时候就需要用managedlist(同理有managedmap,managedset),
managedlist routingconditions = new managedlist(); .... nodewrapdefinition.getpropertyvalues().add("routing", routing);
3.2 注册bean
注册beandefinitionparser 接口的函数中有个参数parsercontext,有个方法为getregistry(),因此,注冊bean的時候就很简单了
parsercontext.getregistry().registerbeandefinition("beanname",nodewrapdefinition);
总结
通过以上三步,就可以实现自己定义标签,并且在spring容器中注入相关的bean。让我们的框架使用起来更方便
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: thinkPHP的表达式查询用法详解