spring自定义标签使用

本文介绍如何在Spring中自定义XML配置文件的命名空间,包括创建自定义xsd文件、配置spring.handlers和spring.schemas文件,以及实现自定义标签解析器。

例如:

<nettyrpc:service id="demoAddService" interfaceName="com.wqh.rpc.services.AddCalculate" ref="calcAddService"></nettyrpc:service>

第一步:自定义xsd文件,nettyrpc.xsd,具体代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.wqh.com/nettyrpc" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:beans="http://www.springframework.org/schema/beans" 
targetNamespace="http://www.wqh.com/nettyrpc" 
elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xsd:import namespace="http://www.springframework.org/schema/beans"/>
	<xsd:element name="service">
		<xsd:complexType>
			<xsd:complexContent>
				<xsd:extension base="beans:identifiedType">
					<xsd:attribute name="interfaceName" type="xsd:string" use="required"/>
					<xsd:attribute name="ref" type="xsd:string" use="required"/>
					<xsd:attribute name="filter" type="xsd:string" use="optional"/>
				</xsd:extension>
			</xsd:complexContent>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>

中的name是用来定义该标签名称
<xsd:extension base="beans:identifiedType"> 定义了该标签的id属性,注意这里引用的是spring-beans中的type
中的type是用来定义该属性的格式,例如
  • xsd:string 表示是一个字符串,对格式没什么要求
  • xsd:id 表示该属性的值是一个id,有格式要求(例如不能以数字开头)。
  • xsd:IDREF 表示该属性的值与某xsd:id属性的值对应
  • 其他还有很多,例如decimal,integer,boolean,date,time等等
中的use是用来定义该属性的使用,例如
  • required 表示是为必须有该属性
  • prohibited 表示该属性禁止使用。
  • optional 表示该属性为选择性属性
详细介绍参见:XSD属性

第二步:自定义配置文件

完成了xsd文件编写后,还需要让该文件生效,就需要在项目的resource/META-INF包里面配置2个文件spring.handlers和spring.schemas

1)spring.handlers

http\://www.wqh.com/nettyrpc=com.wqh.rpc.spring.NettyRpcNamespaceHandler

2)spring.schemas

http\://www.wqh.com/nettyrpc/nettyrpc.xsd=META-INF/nettyrpc.xsd

这样,就可以在Spring的xml配置文件中加入spring.schemas的url,省略掉其他的,在<beans>标签中增加如下标签包引用信息

<beans xmlns:nettyrpc="http://www.wqh.com/nettyrpc" xsi:schemaLocation="http://www.wqh.com/nettyrpc http://www.wqh.com/nettyrpc/nettyrpc.xsd">
完成这步以后,就可以在xml中写自己的标签了,例如自定义标签的namespace为service

<nettyrpc:service id="demoAddService" interfaceName="com.wqh.rpc.services.AddCalculate" ref="calcAddService"></nettyrpc:service>

第二步:自定义标签的解析

在上一步spring.handlers中,我们配置了类com.wqh.rpc.spring.NettyRpcNamespaceHandler作为解析自定义标签的类,所以namespace为service的标签,都会用这里注册的标签解析器来解析

public class NettyRpcNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("service", new NettyRpcServiceParser());
    }
}

我们自定义的标签解析器NettyRpcServiceParser是要实现BeanDefinitionParser 接口的

public class NettyRpcServiceParser implements BeanDefinitionParser {
    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        String interfaceName = element.getAttribute("interfaceName");
        String ref = element.getAttribute("ref");
        String filter = element.getAttribute("filter");

        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(NettyRpcService.class);
        beanDefinition.setLazyInit(false);
        beanDefinition.getPropertyValues().addPropertyValue("interfaceName", interfaceName);
        beanDefinition.getPropertyValues().addPropertyValue("ref", ref);
        beanDefinition.getPropertyValues().addPropertyValue("filter", filter);

        parserContext.getRegistry().registerBeanDefinition(interfaceName, beanDefinition);

        return beanDefinition;
    }
}
对应的BeanClass

public class NettyRpcService implements ApplicationContextAware, ApplicationListener {
    private String interfaceName;
    private String ref;
    private String filter;
    private ApplicationContext applicationContext;

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        ServiceFilterBinder binder = new ServiceFilterBinder();

        if (StringUtils.isBlank(filter) || !(applicationContext.getBean(filter) instanceof Filter)) {
            binder.setObject(applicationContext.getBean(ref));
        } else {
            binder.setObject(applicationContext.getBean(ref));
            binder.setFilter((Filter) applicationContext.getBean(filter));
        }

        MessageRecvExecutor.getInstance().getHandlerMap().put(interfaceName, binder);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
        applicationContext.publishEvent(new ServerStartEvent(new Object()));
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public String getFilter() {
        return filter;
    }

    public void setFilter(String filter) {
        this.filter = filter;
    }

    public String getRef() {
        return ref;
    }

    public void setRef(String ref) {
        this.ref = ref;
    }

    public String getInterfaceName() {
        return interfaceName;
    }

    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }
}

通过以上三步,就可以实现自己定义标签,并且在Spring容器中注入相关的bean。让我们的框架使用起来更方便(更装B)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一屁小肥咩

您的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值