spring自定義標籤使用

例如:

<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)
發佈了102 篇原創文章 · 獲贊 220 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章