首页 > 代码库 > spring 自定义标签 学习

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=http://www.mamicode.com/"1" />>

 

 

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 =http://www.mamicode.com/node.getNodeValue();>

 

这个类会在

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]