spring自定义标签使用

一时失言乱红尘 2022-06-05 02:21 319阅读 0赞

例如:

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

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

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsd:schema xmlns="http://www.wqh.com/nettyrpc"
  3. xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  4. xmlns:beans="http://www.springframework.org/schema/beans"
  5. targetNamespace="http://www.wqh.com/nettyrpc"
  6. elementFormDefault="qualified" attributeFormDefault="unqualified">
  7. <xsd:import namespace="http://www.springframework.org/schema/beans"/>
  8. <xsd:element name="service">
  9. <xsd:complexType>
  10. <xsd:complexContent>
  11. <xsd:extension base="beans:identifiedType">
  12. <xsd:attribute name="interfaceName" type="xsd:string" use="required"/>
  13. <xsd:attribute name="ref" type="xsd:string" use="required"/>
  14. <xsd:attribute name="filter" type="xsd:string" use="optional"/>
  15. </xsd:extension>
  16. </xsd:complexContent>
  17. </xsd:complexType>
  18. </xsd:element>
  19. </xsd:schema>
  20. 中的name是用来定义该标签名称

定义了该标签的id属性,注意这里引用的是spring-beans中的type

  1. 中的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

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

2)spring.schemas

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

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

  1. <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

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

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

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

  1. public class NettyRpcNamespaceHandler extends NamespaceHandlerSupport {
  2. @Override
  3. public void init() {
  4. registerBeanDefinitionParser("service", new NettyRpcServiceParser());
  5. }
  6. }

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

  1. public class NettyRpcServiceParser implements BeanDefinitionParser {
  2. @Override
  3. public BeanDefinition parse(Element element, ParserContext parserContext) {
  4. String interfaceName = element.getAttribute("interfaceName");
  5. String ref = element.getAttribute("ref");
  6. String filter = element.getAttribute("filter");
  7. RootBeanDefinition beanDefinition = new RootBeanDefinition();
  8. beanDefinition.setBeanClass(NettyRpcService.class);
  9. beanDefinition.setLazyInit(false);
  10. beanDefinition.getPropertyValues().addPropertyValue("interfaceName", interfaceName);
  11. beanDefinition.getPropertyValues().addPropertyValue("ref", ref);
  12. beanDefinition.getPropertyValues().addPropertyValue("filter", filter);
  13. parserContext.getRegistry().registerBeanDefinition(interfaceName, beanDefinition);
  14. return beanDefinition;
  15. }
  16. }

对应的BeanClass

  1. public class NettyRpcService implements ApplicationContextAware, ApplicationListener {
  2. private String interfaceName;
  3. private String ref;
  4. private String filter;
  5. private ApplicationContext applicationContext;
  6. @Override
  7. public void onApplicationEvent(ApplicationEvent event) {
  8. ServiceFilterBinder binder = new ServiceFilterBinder();
  9. if (StringUtils.isBlank(filter) || !(applicationContext.getBean(filter) instanceof Filter)) {
  10. binder.setObject(applicationContext.getBean(ref));
  11. } else {
  12. binder.setObject(applicationContext.getBean(ref));
  13. binder.setFilter((Filter) applicationContext.getBean(filter));
  14. }
  15. MessageRecvExecutor.getInstance().getHandlerMap().put(interfaceName, binder);
  16. }
  17. @Override
  18. public void setApplicationContext(ApplicationContext applicationContext)
  19. throws BeansException {
  20. this.applicationContext = applicationContext;
  21. applicationContext.publishEvent(new ServerStartEvent(new Object()));
  22. }
  23. public ApplicationContext getApplicationContext() {
  24. return applicationContext;
  25. }
  26. public String getFilter() {
  27. return filter;
  28. }
  29. public void setFilter(String filter) {
  30. this.filter = filter;
  31. }
  32. public String getRef() {
  33. return ref;
  34. }
  35. public void setRef(String ref) {
  36. this.ref = ref;
  37. }
  38. public String getInterfaceName() {
  39. return interfaceName;
  40. }
  41. public void setInterfaceName(String interfaceName) {
  42. this.interfaceName = interfaceName;
  43. }
  44. }

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

发表评论

表情:
评论列表 (有 0 条评论,319人围观)

还没有评论,来说两句吧...

相关阅读