概述

可以通过扩展Spring的Schema,来实现自定义配置。完成一个自定义配置一般需要完成下面的步骤:

下面是我测试的项目结构:
spring-schema-1.png


编写JavaBean

person.java
package cn.timd.spring.spring_schema;

public class Person {
    private String id;  //id默认是需要的
    private String name;
    private Integer age;

    public Person() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

编写xsd文件

person.xsd
<?xml version="1.0" encoding="UTF-8" ?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://timd.cn/schema/person"
    targetNamespace="http://timd.cn/schema/person"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified">

    <xsd:import namespace="http://www.springframework.org/schema/beans"></xsd:import>

    <xsd:element name="person">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="name" type="xsd:string"></xsd:attribute>
                    <xsd:attribute name="age" type="xsd:int"></xsd:attribute>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>

</xsd:schema>

关于xsd的详细信息,可查看:http://www.w3school.com.cn/schema/index.asp
完成后,需要把xsd放到CLASSPATH下,一般都放在META-INF目录下。


编写NamespaceHandler类和BeanDefinitionParser类

NamespaceHandler类负责根据schema和节点找到相应的BeanDefinitionParser,然后由BeanDefinitionParser完成具体的解析工作。
因此需要分别完成NamespaceHandler和BeanDefinitionParser的实现类,Spring提供了默认实现类NamespaceHandlerSupport和AbstractSingleBeanDefinitionParser,简单的方式就是去继承这两个类。

PersonNamespaceHandler.java
package cn.timd.spring.spring_schema;

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

public class PersonNamespaceHandler extends NamespaceHandlerSupport {
    public void init(){
        registerBeanDefinitionParser("person", new PersonBeanDefinitionParser());
    }
}

registerBeanDefinitionParser用来把节点名和解析类关联起来

PersonBeanDefinitionParser.java
package cn.timd.spring.spring_schema;

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 PersonBeanDefinitionParser extends AbstractSingleBeanDefinitionParser  {

    protected Class getBeanClass(Element element) {
        return Person.class;
    }

    protected void doParse(Element ele, BeanDefinitionBuilder bean) {
        String id = ele.getAttribute("id");
        String name = ele.getAttribute("name");
        String age = ele.getAttribute("age");

        if (StringUtils.hasText(id))
            bean.addPropertyValue("id", Integer.valueOf(id));
        if (StringUtils.hasText(name))
            bean.addPropertyValue("name", name);
        if (StringUtils.hasText(age))
            bean.addPropertyValue("age", Integer.valueOf(age));
    }
}

ele.getAttribute用于从配置中取得属性值,bean.addPropertyValue用于把属性值放到bean中

编写spring.handlers和spring.schemas

spring.handlers和spring.schemas用于串联所有的组件---xsd文件、NamespaceHandler类以及BeanDefinitionParser类。这两个文件必须放在META-INF下(xsd文件可以放在META-INF下,也可以放在类路径下)。

http\://timd.cn/schema/person=cn.timd.spring.spring_schema.PersonNamespaceHandler
http\://timd.cn/schema/person/person.xsd=META-INF/person.xsd

在Bean配置文件中使用

applicationContext.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:person="http://timd.cn/schema/person"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://timd.cn/schema/person
       http://timd.cn/schema/person/person.xsd">

    <person:person name="timchow" age="28" id="10086"></person:person>

</beans>

Main.java
package cn.timd.spring.spring_schema;

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

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) ctx.getBean("10086");
        System.out.println(person);
    }
}