spring 自定义标签 学习

自定义配置文件到spring 中,有时候想做一些数据结构的配置化信息,根据业务做一个扩展。

首先:

在项目的META-INF目录下新建两个文件spring.handlers,和spring.shcemas

Spring.handlers在类org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver中已经写死了要取mapping的handlerMappingsLocation的路径

public static finalString DEFAULT_HANDLER_MAPPINGS_LOCATION ="META-INF/spring.handlers";

Spring.Schemas 在org.springframework.beans.factory.xml.PluggableSchemaResolver这个类中

同样写死了位置

public static finalString DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";

初始化的时候第一次调用的时候会调用

PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation,this.classLoader)

把所有的文件名包含的取出来放入map中。

spring.handlers内容:

http\://www.ruishenh.com/custom/mytest=com.ruishenh.spring.config.MyNamespaceHandler

spring.schemas内容:

http\://www.ruishenh.com/custom/mytest/myTest.xsd=customTag/myTest.xsd

customTag/myTest.xsd文件:

<?xml version="1.0"encoding="UTF-8"?>
<xsd:schema xmlns="http://www.ruishenh.com/custom/myTest"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ruishenh.com/custom/mytest"
    elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xsd:element name="executor">
        <xsd:complexType>
            <xsd:attribute name="name" type="xsd:string">
            </xsd:attribute>
            <xsd:attribute name="delay" type="xsd:int">
            </xsd:attribute>
            <xsd:attribute name="interval" type="xsd:int"use="required">
            </xsd:attribute>
            <xsd:attribute name="address" type="xsd:string">
            </xsd:attribute>
            <xsd:attribute name="entity" type="xsd:string">
            </xsd:attribute>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="entity">
        <xsd:complexType>
            <xsd:attribute name="name" type="xsd:string">
                <xsd:annotation>
                    <xsd:documentation><![CDATA[ bean Name ]]></xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
            <xsd:attribute name="splitBy" type="xsd:string">
                <xsd:annotation>
                    <xsd:documentation xml:lang="zh"><![CDATA[ sqoop分割字段 ]]></xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
            <xsd:attribute name="sql" type="xsd:string">
                <xsd:annotation>
                    <xsd:documentation xml:lang="zh"><![CDATA[数据库操作sql]]></xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
            <xsd:attribute name="dbTypeID">
                <xsd:annotation>
                    <xsd:documentation xml:lang="zh">
                    <![CDATA[ 指定数据库类型 如果类型不存在就判断dbTypeName属性,1是mysql,2是oracle,3是sqlserver    ]]>
                    </xsd:documentation>
                </xsd:annotation>
                <xsd:simpleType>
                    <xsd:restriction base="xsd:int">
                        <xsd:enumeration value="1" />
                        <xsd:enumeration value="2" />
                        <xsd:enumeration value="3" />
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:attribute>
            <xsd:attribute name="dbTypeName">
                <xsd:annotation>
                    <xsd:documentation xml:lang="zh"><![CDATA[ 指定数据库指定名称  如果  dbTypeID 不存在就取当前值 ]]></xsd:documentation>
                </xsd:annotation>
                <xsd:simpleType>
                    <xsd:restriction base="xsd:string">
                        <xsd:enumeration value="mysql" />
                        <xsd:enumeration value="oracle" />
                        <xsd:enumeration value="sqlserver" />
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:attribute>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

spring/myTest.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:mi="http://www.ruishenh.com/custom/mytest"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.ruishenh.com/custom/mytesthttp://www.ruishenh.com/custom/mytest/myTest.xsd">

    <mi:entity dbTypeID="1" dbTypeName="mysql"splitBy="id" sql="1"
        name="mye" />
    <mi:executor interval="5000" address="127.0.0.1"delay="2000"
        name="myexecutor" entity="mye" />
</beans>

com.ruishenh.spring.config.MyNamespaceHandler  命名空间处理类:

package com.ruishenh.spring.config;

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

public class MyNamespaceHandler extends NamespaceHandlerSupport{

    @Override
    public void init() {
        registerBeanDefinitionParser("executor",newMyBeanDefinitionParser(MyExecutor.class));
        registerBeanDefinitionParser("entity",newMyBeanDefinitionParser(MyEntity.class));
    }

}

这个类主要是在DefaultNamespaceHandlerResolver这个类中getHandlerMappings()取到了所有的META-INF/spring.handlers的文件内容存入map,然后根据当前的命名空间找到对应的NamespaceHandler,然后反射出对象调用init()

Class<?> handlerClass =ClassUtils.forName(className, this.classLoader);
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)){
                    throw new FatalBeanException("Class ["+ className + "] for namespace [" + namespaceUri +
                            "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                }
                NamespaceHandlernamespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                namespaceHandler.init();

com.ruishenh.spring.config.MyBeanDefinitionParser解析类:

packagecom.ruishenh.spring.config;

importorg.springframework.beans.factory.config.BeanDefinition;
importorg.springframework.beans.factory.config.RuntimeBeanReference;
importorg.springframework.beans.factory.support.RootBeanDefinition;
importorg.springframework.beans.factory.xml.BeanDefinitionParser;
importorg.springframework.beans.factory.xml.ParserContext;
importorg.w3c.dom.Element;
importorg.w3c.dom.NamedNodeMap;
importorg.w3c.dom.Node;

public classMyBeanDefinitionParser implements BeanDefinitionParser {

         private Class<?> clssze;

         publicMyBeanDefinitionParser(Class<?> cls) {
                   this.clssze = cls;
         }

         @Override
         public BeanDefinition parse(Elementelement, ParserContext parserContext) {
                   RootBeanDefinitionbeanDefinition = new RootBeanDefinition();
                   beanDefinition.setBeanClass(clssze);
                   String id = null;
                   id =element.getAttribute("name");
                   if (id == null) {
                            if (clssze ==MyExecutor.class) {
                                     id = "test_myExecutor";
                            } else if (clssze ==MyEntity.class) {
                                     id ="test_myentity";
                            } else {
                                     throw newIllegalStateException("MyBeanDefinitionParser.parse,未知的业务逻辑处理:class:" +element.getAttribute("class"));
                            }
                   }
                   int counter = 2;
                   while(parserContext.getRegistry().containsBeanDefinition(id)) {
                            id = id +(counter++);
                   }
                   if (id != null &&id.length() > 0) {
                            if(parserContext.getRegistry().containsBeanDefinition(id)) {
                                     throw newIllegalStateException("Duplicate spring bean id " + id);
                            }
                            parserContext.getRegistry().registerBeanDefinition(id,beanDefinition);
                   }
                   NamedNodeMap nnm =element.getAttributes();
                   for (int i = 0; i <nnm.getLength(); i++) {
                            Node node =nnm.item(i);
                            String key =node.getLocalName();
                            String value =node.getNodeValue();
                            if(key.equals("entity")) {
                                     if(parserContext.getRegistry().containsBeanDefinition(value)) {
                                               beanDefinition.getPropertyValues().add(key,parserContext.getRegistry().getBeanDefinition(value));
                                     } else {
                                               beanDefinition.getPropertyValues().add(key,new RuntimeBeanReference(value));
                                     }
                            } else {
                                     beanDefinition.getPropertyValues().add(key,value);
                            }
                   }

                   return beanDefinition;
         }
}

这个类会在

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Elementroot, BeanDefinitionParserDelegate delegate)这个方法中入口执行

然后到org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(Elementelement, ParserContext parserContext);

最后找到对应的BeanDefinitionParser执行parse方法。至于放入BeanDefinitionParser的入口就在自定义的NamespaceHandler中init()方法中。

com/ruishenh/spring/config/MyEntity.java实体类:

package com.ruishenh.spring.config;

import com.ruishenh.model.BaseModel;

public classMyEntity extendsBaseModel{

    private int dbTypeID;

    private String dbTypeName;

    private String splitBy;

    private String sql;

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSplitBy() {
        return splitBy;
    }

    public void setSplitBy(StringsplitBy) {
        this.splitBy = splitBy;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    public int getDbTypeID() {
        return dbTypeID;
    }

    public void setDbTypeID(int dbTypeID) {
        this.dbTypeID = dbTypeID;
    }

    public String getDbTypeName(){
        return dbTypeName;
    }

    public void setDbTypeName(StringdbTypeName) {
        this.dbTypeName = dbTypeName;
    }

}
 

com/ruishenh/spring/config/MyExecutor.java实体类:

package com.ruishenh.spring.config;

import com.ruishenh.model.BaseModel;

public classMyExecutor  extends BaseModel{

    private String name;

    private int delay;

    private int interval;

    private String address;

    private MyEntity entity;

    public MyEntity getEntity() {
        return entity;
    }

    public void setEntity(MyEntity entity) {
        this.entity = entity;
    }

    public int getDelay() {
        return delay;
    }

    public void setDelay(int delay) {
        this.delay = delay;
    }

    public int getInterval() {
        return interval;
    }

    public void setInterval(int interval) {
        this.interval = interval;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(Stringaddress) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

测试类:

package com.ruishenh.spring.test;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.ruishenh.spring.config.MyEntity;
import com.ruishenh.spring.config.MyExecutor;

public classTest {
    public static void main(String[] args) {
        Stringconf = "classpath:spring/myTest.xml";
        FileSystemXmlApplicationContextac = newFileSystemXmlApplicationContext(conf);
        MyExecutorme = ac.getBean(MyExecutor.class);
        System.out.println(me.toString());
        MyEntity mye = ac.getBean(MyEntity.class);
        System.out.println(mye.toString());
    }
}
 

运行结果:

MyExecutor[name=myexecutor,delay=2000,interval=5000,address=127.0.0.1,entity=MyEntity[dbTypeID=1,dbTypeName=mysql,splitBy=id,sql=1,name=mye]]

MyEntity[dbTypeID=1,dbTypeName=mysql,splitBy=id,sql=1,name=mye]

spring 自定义标签 学习

时间: 2024-10-03 14:55:54

spring 自定义标签 学习的相关文章

spring 自定义标签 学习二

在上篇中写的只支持写属性,不支持标签property的写法,但是如果有时候我们还想做成支持 property的用法,则可以在xsd中增加spring 自带的xsd引用 修改xsd文件如下: <?xml version="1.0"encoding="UTF-8"?> <xsd:schema xmlns="http://www.ruishenh.com/custom/myTest" xmlns:xsd="http://ww

Spring 自定义标签配置

前景:经常使用一些依赖于Spring的组件时,发现可以通过自定义配置Spring的标签来实现插件的注入,例如数据库源的配置,Mybatis的配置等.那么这些Spring标签是如何自定义配置的?学习Spring标签的自定义配置为以后实现分布式服务框架做技术储备. 技术分析:Spring的标签配置是通过XML来实现的,通过XSD(xml Schema Definition)来定义元素,属性,数据类型等. Spring自定义标签解析 1.Spring启动时通过扫描根目录下的META-INF文件下的sp

(转载)Spring自定义标签的原理

Spring自定义标签的原理 XML通常通过DTD.XSD定义,但DTD的表达能力较弱,XSD定义则能力比较强,能够定义类型,出现次数等.自定义标签需要XSD支持,在实现时使用Namespace扩展来支持自定义标签. <bean id="beanId" class="com.xxx.xxxx.Xxxxx"> <property name="property1"> <value>XXXX</value>

Spring 自定义标签

Spring 工作流程是先加载解析xml配置文件:配置文件中存在默认的标签,也可以自定义标签.解析默认标签调用: 1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { 2 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { 3 importBeanDefinitionResource(ele); 4 } 5 else if

dubbo源码学习(二) : spring 自定义标签

做dubbo的配置时很容易发现,dubbo有一套自己的标签,提供给开发者配置,其实每一个标签对应着一个 实体,在容器启动的时候,dubbo会对所有的配置进行解析然后将解析后的内容设置到实体里,最终dubbo会根据实体中的值生成贯穿全局的统一URL.利用自定义标签使配置简单明了化,与spring完美融合.下面自己写一个自定义标签,主要需要如下 几个步骤: 1.编写实体类2.编写Parser解析类3.编写NameSpaceHandle类4.配置spring.handlers5.配置spring.sc

自己构建一个Spring自定义标签以及原理讲解

平时不论是在Spring配置文件中引入其他中间件(比如dubbo),还是使用切面时,都会用到自定义标签.那么配置文件中的自定义标签是如何发挥作用的,或者说程序是如何通过你添加的自定义标签实现相应的功能的呢?且看下文. 通过对本文的阅读,你会在阅读涉及到自定义标签的源码功能时事半功倍,而且还可以自己动手做出一个自己的自定义标签. 先呈上我自己在本地实现自定义标签的代码及对应讲解: 1.先无脑输出一个测试要用到的Bean类 1 public class User { 2 3 private Stri

Spring自定义标签

一.原理: 1.Spring通过XML解析程序将其解析为DOM树, 2.通过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDefinition. 3.再通过Spring自身的功能对BeanDefinition实例化对象. 二.自定义标签步骤 1.定义三个文件 META-INF/spring.handlers http\://www.newlandframework.com/dubbo=com.newlandframewor

Servlet和JSP之自定义标签学习

  此文章会讲述简单标签处理器,因为经典自定义标签处理器没有简单标签处理器方便使用,故在此不进行描述. 参考:慕课网的<JSP自定义标签>视频; <Servlet.JSP和Spring MVC初学指南>的第六章; IBM的<利用 JSP 2 提供的 SimpleTagSupport 开发自定义标签>; 菜鸟教程的JSP自定义标签文章. 自定义标签   自定义标签 自定义标签就是将方法封装到自定义标签处理类中,然后使用方法与JSTL标签来达到,解决JSP中JavaBean

Spring的自定义标签

当Spring拿到一个元素时首先要做的是根据命名空间进行解析,如果是默认的命名空间,则使用parseDefaultElement方法进行元素解析,否则使用parseCustom Element方法进行解析. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl =