spring的自定义标签

1:写在前面

spring默认提供的标签,我们常用的bean标签,property,constructor-arg等,spring也允许我们自定义标签。

2:默认标签的解析过程

我们这里以xsd约束文件为例,来简单描述,首先需要有一个xsd的约束文件,然后需要有一个spring.schema文件来描述命名空间和xsd文件的对应关系,这些在自定义标签的时候也是必不可少的,除此之外我们自定义的标签还需要一个解析的类,因此还需要有这样的一个类,在spring中这个类必须实现org.springframework.beans.factory.xml.NamespaceHandler接口,实际中我们只需要继承org.springframework.beans.factory.xml.NamespaceHandlerSupport抽象子类就可以了,下面就让我们一个一个的实现这些必须条件吧。

3:实例

3.1:例子说明

自定义标签,实现bean标签的作用,即完成创建一个spring bean的工作。

3.2:定义xsd约束文件

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://dongshi.daddy.com/schema/ok"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://dongshi.daddy.com/schema/ok"
            elementFormDefault="qualified">
    <!-- 定义service顶层标签,其类型是复杂类型server -->
    <xsd:element name="service" type="server">
        <xsd:annotation>
            <xsd:documentation><![CDATA[ The service config ]]></xsd:documentation>
        </xsd:annotation>
    </xsd:element>

    <!-- 定义server类型可以有哪些属性 -->
    <xsd:complexType name="server">
        <xsd:attribute name="id" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="serverName" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The name of the bean. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
    </xsd:complexType>
</xsd:schema>

表达的含义是,在service标签中可以有id属性,serverName属性。最后将该文件放在resources资源文件目录下,文件命名为dongshidaddy-1.0.xsd,后续配置会用到该名称。其中的targetNamespace="http://dongshi.daddy.com/schema/ok"是设置该约束文件的命名空间是http://dongshi.daddy.com/schema/ok

3.3:配置xsd约束文件

需要在spring.schemas中配置,并且该文件需要放在classpath下的META-INF文件夹下,因此需要先在resources下定义该文件夹,定义内容如下:

http\://dongshi.daddy.com/schema/ok/ok-1.0.xsd=./dongshidaddy-1.0.xsd

3.4:定义解析自定义标签的类

注意实现接口org.springframework.beans.factory.xml.BeanDefinitionParser,主要代码已经添加了注释:

public class CommonNamespaceHandler extends NamespaceHandlerSupport {
    
    

    @Override
    public void init() {
    
    
        this.registerBeanDefinitionParser("service",
                new OkServerDefinitionParser(ServerBean.class));
    }
}

OkServerDefinitionParser:

public class OkServerDefinitionParser implements BeanDefinitionParser {
    
    

    private final Class<?> clazz;
    private static final String default_prefix = "ok-";
    private static final AtomicLong COUNT = new AtomicLong(0);

    public OkServerDefinitionParser(Class<?> clazz) {
    
    
        this.clazz = clazz;
    }

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
    
    
        return parseHelper(element, parserContext, this.clazz);
    }

    private BeanDefinition parseHelper(Element element, ParserContext parserContext, Class<?> clazz) {
    
    
        // 创建封装信息的beandefinition
        RootBeanDefinition bd = new RootBeanDefinition();
        // 不延迟加载
        bd.setLazyInit(false);
        String id = element.getAttribute("id");
        if (id == null || id.isEmpty()) {
    
    
            id = default_prefix + COUNT.getAndDecrement();
        }
        // 获取配置的serverName的值
        String serverName = element.getAttribute("serverName");
        // 设置class
        bd.setBeanClass(clazz);
        // 设置初始化方法的名称
        bd.setInitMethodName("init");

        // 从beandefinition中获取存储属性名称->属性值新的对象
        MutablePropertyValues propertyValues = bd.getPropertyValues();
        // 添加serverName属性和其值到可修改属性值对象中
        propertyValues.addPropertyValue("serverName", serverName);
        // 通过注册机注册BeanDefinition信息,最终会存储到一个map中,key就是id,value就是BeanDefinition
        parserContext.getRegistry().registerBeanDefinition(id, bd);
        // 返回创建的BeanDefinition,后续spring就会使用这个BeanDefinition对象来创建spring bean了
        return bd;
    }
}

ServerBean:

public class ServerBean {
    
    
    private String serverName;

    //init method
    public void init() {
    
    
        System.out.println("bean ServerBean init.");
    }

    @Override
    public String toString() {
    
    
        return "[Service]=>" + serverName;
    }

    public String getServerName() {
    
    
        return serverName;
    }

    public void setServerName(String serverName) {
    
    
        this.serverName = serverName;
    }
}

3.5:注册解析类

META-INF下创建文件spring.handlers文件,如下:

http\://dongshi.daddy.com/schema/ok=yudaosourcecode.selfdefinetag.CommonNamespaceHandler

意思是如果是命名空间是http\://dongshi.daddy.com/schema/ok则使用解析类yudaosourcecode.selfdefinetag.CommonNamespaceHandler

3.6:定义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:ok="http://dongshi.daddy.com/schema/ok"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://dongshi.daddy.com/schema/ok
           http://dongshi.daddy.com/schema/ok/dongshidaddy-1.0.xsd">
    <ok:service id="testServer" serverName="HelloWorldService"/>
</beans>

其中xmlns:ok="http://dongshi.daddy.com/schema/ok"定了命名空间http://dongshi.daddy.com/schema/ok使用前缀<ok:来定义,并在xsi:schemaLocation中声明了约束文件的位置。

3.7:测试代码

@Test
public voidtestSelfDefineTag() {
    
    
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("testselfdefinetag.xml");
    ServerBean testServer = ac.getBean("testServer", ServerBean.class);
    System.out.println(testServer);
}

运行:

bean ServerBean init.
[Service]=>HelloWorldService

Process finished with exit code 0

猜你喜欢

转载自blog.csdn.net/wang0907/article/details/114408134