基于Spring开发之自定义标签及其解析

时间:2021-05-19

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\://.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。让我们的框架使用起来更方便

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

    声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

    相关文章