欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring 扩展自定义标签案例实现

程序员文章站 2022-04-29 23:39:35
...

在很多情况下,我们需要为系统提供可配置化支持,简单的做法可以直接基于Spring的标准Bean来配置,但配置较为复杂或者需要更多丰富控制的 时候,会显得非常笨拙。一般的做法会用原生态的方式去解析定义好的xml文件,然后转化为配置对象,这种方式当然可以解决所有问题,但实现起来比较繁琐, 特别是是在配置非常复杂的时候,解析工作是一个不得不考虑的负担。Spring提供了可扩展Schema的支持,这是一个不错的折中方案。

扩展Spring自定义标签大致需要如下几步:

1.创建需要扩展的组件(设计配置属性和JavaBean)

2.定义XSD文件描述组件内容(自定义的合法构建模块),主要用于定义数据约束;

3.创建一个文件,实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件定义

4.创建Handler文件,扩展字NamespaceHandlerSupport,目的是将组件注册到Spring容器

5.编写Spring.handlers和Spring.schemas文件

6.搞定可以在应用中使用了

设计配置属性和JavaBean

首先当然得设计好配置项,并通过JavaBean来建模,本例中需要配置People实体,配置属性name和age(id是默认需要的)

public class MyBeanJavaBean {
    //默认需要
    private String id;
    private String name;
    private String url;
    
     ...省略set get方法...
}

编写XSD文件

为上一步设计好的配置项编写XSD文件,XSD是schema的定义文件,配置的输入和解析输出都是以XSD为契约,本例中XSD如下:src/main/resources/META-INF/MyBeanJavaBean.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
        xmlns="http://www.example.org/schema/MyBeanJavaBean"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:beans="http://www.springframework.org/schema/beans"
        targetNamespace="http://www.example.org/schema/MyBeanJavaBean"
        elementFormDefault="qualified"
        attributeFormDefault="unqualified">

    <xsd:import namespace="http://www.springframework.org/schema/beans" />
    <xsd:element name="MyBeanJavaBean">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="name" type="xsd:string" />
                    <xsd:attribute name="url" type="xsd:string" />
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

描述了一个targetNamespace,并且创建了一个element MyBeanJavaBean。里面有三个attribute。主要是为了验证Spring配置文件中的自定义格式。再进一步解释,就是,Spring位置文件中使用的MyBeanJavaBean自定义标签中,属性只能是上面的三种,有其他的属性的话,就会报错。

关于xsd:schema的各个属性具体含义就不作过多解释,可以参见http://www.w3school.com.cn/schema/schema_schema.asp

<xsd:element name="people">对应着配置项节点的名称,因此在应用中会用people作为节点名来引用这个配置

<xsd:attribute name="name" type="xsd:string" />对应着属性名和类型

完成后需把xsd存放在classpath下,一般都放在META-INF目录下(本例就放在这个目录下)

编写NamespaceHandler和BeanDefinitionParser完成解析工作

下面需要完成解析工作,会用到NamespaceHandler和BeanDefinitionParser这两个概念。具体说来 NamespaceHandler会根据schema和节点名找到某个BeanDefinitionParser,然后由 BeanDefinitionParser完成具体的解析工作。因此需要分别完成NamespaceHandler和 BeanDefinitionParser的实现类,Spring提供了默认实现类NamespaceHandlerSupport和 AbstractSingleBeanDefinitionParser,简单的方式就是去继承这两个类。

创建文件,实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件定义

package org.alexsotob.spring.extension;


import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

public class MyBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    @SuppressWarnings("rawtypes")
    protected Class getBeanClass(Element element) {
        return MyBeanJavaBean.class;
    }

    /**
     * 解析节点数据
     */
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        String userName = element.getAttribute("name");
        String email = element.getAttribute("url");
        if (StringUtils.hasText(userName)) {
            bean.addPropertyValue("userName", userName);
        }
        if (StringUtils.hasText(email)){
            bean.addPropertyValue("email", email);
        }

    }
}

上文,虽说是继承了AbstractSingleBeanDefinitionParser ,但根本上来说,是实现了BeanDefinitionParser接口。

创建扩展NamespaceHandler

扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器中。

package org.alexsotob.spring.extension;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class MyBeanNamespaceHandler extends NamespaceHandlerSupport {

    public void init() {

        registerBeanDefinitionParser("MyBean", new MyBeanDefinitionParser());
        
    }
}

编写Spring.handlers和Spring.schemas文件

上面几个步骤走下来会发现开发好的handler与xsd还没法让应用感知到,就这样放上去是没法把前面做的工作纳入体系中的,spring提供了 spring.handlers和spring.schemas这两个配置文件来完成这项工作,这两个文件需要我们自己编写并放入META-INF文件夹 中,这两个文件的地址必须是META-INF/spring.handlers和META-INF/spring.schemas,spring会默认去 载入它们

路径:

src/main/resources/META-INF/spring.handlers

src/main/resources/META-INF/spring.schemas 

Spring 扩展自定义标签案例实现

根据对应的命名空间找到对应的xsd文件以及handler类

创建测试配置文件

路径:src/main/resources/test.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:myBean="http://www.example.org/schema/MyBeanJavaBean"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.example.org/schema/MyBeanJavaBean http://www.example.org/schema/MyBeanJavaBean.xsd">

    <myBean:MyBean id = "firstMyBean" name = "lee" url = "www.baidu.com"/>

</beans>

在第4行这里引入了myBean对应的命名空间,它会到第六行(http://www.example.org/schema/MyBeanJavaBean.xsd)找到对应XSD文件进行check。第六行的http://www.example.org/schema/MyBeanJavaBean.xsd 找到对应的文件的位置,在前面spring.schemas可以找到

编写测试

package org.alexsotob.spring.extension;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext beans=new ClassPathXmlApplicationContext("classpath:test.xml");
        MyBeanJavaBean myBean=(MyBeanJavaBean)beans.getBean("firstMyBean");
        System.out.println(myBean);
    }
}

最后效果

Spring 扩展自定义标签案例实现 

本此主要讲解的是如何自定实现标签解析,那么思考????,spring是如何扩展能让我们自定标签,并且能和本身的程序代码进行融合呢?后面会继续讲解,一起努力 

 

 

 

 

相关标签: 框架 spring