要想自定义标签,首先第一步须要写本身的XML Schema。XML Schema的我的感受比较复杂,网上的教程比较简单,所以能够参照spring-beans.xsd依葫芦画瓢。这里就按照我本身的理解进行简单介绍一下吧。 ##1.1 最简单的标签 一个最简单的标签,形式如:node
<bf:head-routing key="1" value="1" to="test2"/>
该标签只包含了若干属性,咱们就在xsd文件中这么定义spring
<!-- 声明一个标签,名字为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是用来定义该属性的格式,例如app
所谓复杂,其实就是嵌套的标签,形式如:框架
<bf:stop id="test1" ref="testNode"> <bf:head-routing key="1" value="1" to="test2"/> </bf:stop>
其实只要参照Spring 中<bean>标签的xsd依葫芦画瓢,首先是定义stop标签ide
<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: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"/> -->
完成了xsd文件编写后,还须要让该文件生效,就须要在项目的resource/META-INF包里面配置2个文件spring.handlers和spring.schemasui
改配置文件主要是用一个url来映射咱们第一步配置好的文件,形式以下url
http\://www.lizo.com/schema/bf.xsd=META-INF/bf.xsd
这样,就能够在Spring的xml配置文件中加入spring.schemas的url,省略掉其余的,在<beans>标签中增长以下信息spa
<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,code
<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>
这个配置文件用来配置解析咱们bf标签,而后生成一些BeanDefinition进行注册。例如
http\://www.lizo.com/schema/bf=com.lizo.config.BusinessFlowNamespaceHandlerSupport
其中 BusinessFlowNamespaceHandlerSupport就是咱们用来解析标签
在上一步中,咱们配置了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经过设置Class和属性的注入就能够完成。以下:
RootBeanDefinition nodeWrapDefinition = new RootBeanDefinition(); //该BeanDefinition对应的是什么类 nodeWrapDefinition.setBeanClass(StationRoutingWrap.class); //name是解析标签后得到的值 nodeWrapDefinition.getPropertyValues().addPropertyValue("name", name);
RuntimeBeanReference 用于在运行时去获取BeanDefinition,由于在咱们建立这个BeanDefinition的时候咱们只知道他的beanName,并不肯定是否已经注册了,这个时候就须要用RuntimeBeanReference,例如
RuntimeBeanReference refBean = new RuntimeBeanReference(ref); nodeWrapDefinition.getPropertyValues().addPropertyValue("station", refBean);
某个BeanDefinition注入的属性为一个List,这个时候就须要用ManagedList(同理有ManagedMap,ManagedSet),
ManagedList routingConditions = new ManagedList(); .... nodeWrapDefinition.getPropertyValues().add("routing", routing);
注册BeanDefinitionParser 接口的函数中有个参数ParserContext,有个方法为getRegistry(),所以,注冊bean的時候就很简单了
parserContext.getRegistry().registerBeanDefinition("beanName",nodeWrapDefinition);
经过以上三步,就能够实现本身定义标签,而且在Spring容器中注入相关的bean。让咱们的框架使用起来更方便(更装B)