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

 更新时间:2017年04月25日 08:57:50   作者:lizo  
Spring框架是现在Java最流行的开源框架之一,需要实现一些自定义的标签,主要是方便使用我们框架的人能够快速、简单进行配置,有兴趣的可以了解一下。

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是用来定义该属性的格式,例如

  1. xsd:string 表示是一个字符串,对格式没什么要求
  2. xsd:id 表示该属性的值是一个id,有格式要求(例如不能以数字开头)。
  3. xsd:IDREF 表示该属性的值与某xsd:id属性的值对应
  4. 其他还有很多,例如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的基本流程为:

  1. 解析标签
  2. 根据解析的值生成BeanDefinition,
  3. 注册标签

解析标签就不用说,重点说说怎么生成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。让我们的框架使用起来更方便

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

相关文章

  • 如何使用java写Student类的功能

    如何使用java写Student类的功能

    这篇文章主要介绍了如何使用java写Student类的功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • Netty学习教程之基础使用篇

    Netty学习教程之基础使用篇

    Netty是由JBOSS提供的一个Java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。下面这篇文章主要给大家介绍了关于Netty基础使用的相关资料,需要的朋友可以参考下。
    2017-05-05
  • 如何解决Spring的UnsatisfiedDependencyException异常问题

    如何解决Spring的UnsatisfiedDependencyException异常问题

    这篇文章主要介绍了如何解决Spring的UnsatisfiedDependencyException异常问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • Spring boot实现一个简单的ioc(2)

    Spring boot实现一个简单的ioc(2)

    这篇文章主要为大家详细介绍了Spring boot实现一个简单ioc的第二篇,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • springboot简单实现单点登录的示例代码

    springboot简单实现单点登录的示例代码

    本文主要介绍了springboot简单实现单点登录的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Springboot项目如何使用apollo配置中心

    Springboot项目如何使用apollo配置中心

    这篇文章主要介绍了Springboot项目如何使用apollo配置中心,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • java构造函数示例(构造方法)

    java构造函数示例(构造方法)

    这篇文章主要介绍了java构造函数示例(构造方法),需要的朋友可以参考下
    2014-03-03
  • Java设计模块系列之书店管理系统单机版(三)

    Java设计模块系列之书店管理系统单机版(三)

    这篇文章主要为大家详细介绍了Java单机版的书店管理系统设计模块和思想第三章,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • Java实现用户短信验证码登录功能实例代码

    Java实现用户短信验证码登录功能实例代码

    现在不管是各类的网站,还是大小社交app,登录方式是越来越多了,但是大部分还是以短信登录为主,本文主要介绍了java短信验证码登录功能设计与实现,感兴趣的可以了解一下
    2021-11-11
  • spring框架下@value注解属性static无法获取值问题

    spring框架下@value注解属性static无法获取值问题

    这篇文章主要介绍了spring框架下@value注解属性static无法获取值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11

最新评论