zoukankan      html  css  js  c++  java
  • 聊聊自定义SPI如何使用自定义标签注入到spring容器中

    前言

    之前我们聊过自定义的SPI如何与spring进行整合,今天我们就来聊下如何通过自定义标签将spi对象注入到spring容器中

    实现套路

    1、自定义xsd

    示例

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:beans="http://www.springframework.org/schema/beans"
                xmlns:tool="http://www.springframework.org/schema/tool"
                xmlns="http://lybgeek.github.com/schema/spi"
                targetNamespace="http://lybgeek.github.com/schema/spi">
    
        <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
        <xsd:import namespace="http://www.springframework.org/schema/beans"
                    schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd"/>
        <xsd:import namespace="http://www.springframework.org/schema/tool"/>
    
        <xsd:annotation>
            <xsd:documentation>
                <![CDATA[ Namespace support for spi services ]]></xsd:documentation>
        </xsd:annotation>
    
    
        <xsd:complexType name="scanType">
            <xsd:attribute name="id" type="xsd:ID">
                <xsd:annotation>
                    <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
            <xsd:attribute name="basePackages" type="xsd:string" use="required">
                <xsd:annotation>
                    <xsd:documentation><![CDATA[ Specify the spi package name to scan, multiple scan packages are separated by commas ]]></xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
        </xsd:complexType>
    
        <xsd:complexType name="interceptorType">
            <xsd:attribute name="id" type="xsd:ID">
                <xsd:annotation>
                    <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
            <xsd:attribute name="class" type="xsd:string" use="required">
                <xsd:annotation>
                    <xsd:documentation><![CDATA[ Interceptor class name]]></xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
        </xsd:complexType>
    
        <xsd:complexType name="interceptorChainType">
            <xsd:choice>
                <xsd:element ref="interceptor" minOccurs="1" maxOccurs="unbounded"/>
            </xsd:choice>
        </xsd:complexType>
    
    
        <xsd:element name="scan" type="scanType">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The scan config ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:element>
    
        <xsd:element name="interceptor" type="interceptorType">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The interceptor config ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:element>
    
        <xsd:element name="interceptorChain" type="interceptorChainType">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The interceptorChainType config ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:element>
    
    </xsd:schema>
    
    

    ps: 如果对xsd不熟悉的朋友,可以参考如下链接

    https://www.w3school.com.cn/schema/index.asp

    2、自定义解析BeanDefinitionParser解析器

    示例:

    public class AnnotationBeanDefinitionParser implements BeanDefinitionParser {
    
        private final Class<?> beanClass;
    
        public AnnotationBeanDefinitionParser(Class<?> beanClass) {
            this.beanClass = beanClass;
        }
    
        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
    
            String packageToScan = element.getAttribute("basePackages");
            String[] packagesToScan = trimArrayElements(commaDelimitedListToStringArray(packageToScan));
    
            RootBeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClass(beanClass);
            beanDefinition.setLazyInit(false);
            beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,packagesToScan);
            String beanName = BeanUtils.generateBeanName(element,"id",parserContext,beanClass.getName());
            parserContext.getRegistry().registerBeanDefinition(beanName,beanDefinition);
    
            return beanDefinition;
        }
    
    
    }
    

    3、定义NamespaceHandler实现类处理自定义标签的处理器

    示例:

    public class SpiNamespaceHandler extends NamespaceHandlerSupport {
    
        @Override
        public void init() {
            registerBeanDefinitionParser("scan", new AnnotationBeanDefinitionParser(SpiAnnotationPostProcessor.class));
        }
    }
    

    4、将写入处理器、标签的位置写入spring.handlers、spring.schemas中

    示例:

    spring.handlers

    http\://lybgeek.github.com/schema/spi=com.github.lybgeek.spring.schema.SpiNamespaceHandler
    

    spring.schemas

    http\://lybgeek.github.com/schema/spi/spi.xsd=META-INF/spi/spi.xsd
    

    注: spring.handlers、spring.schemas需放置在resource/META-INF目录底下

    示例演示

    1、配置xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:spi="http://lybgeek.github.com/schema/spi"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://lybgeek.github.com/schema/spi http://lybgeek.github.com/schema/spi/spi.xsd">
    
        <spi:scan basePackages="com.github.lybgeek"></spi:scan>
    
    
    

    2、在启动类上导入xml

    @SpringBootApplication
    @ImportResource(locations = "classpath:/spi.xml")
    public class SpiTestXmlApplication {
    
    
        public static void main(String[] args) throws Exception{
            SpringApplication.run(SpiTestXmlApplication.class);
        }
    
    
    }
    

    3、验证SPI是否注入spring容器

     @Override
        public void run(ApplicationArguments args) throws Exception {
    
            applicationContext.getBeansOfType(SpringSqlDialect.class)
                    .forEach((beanName,bean) -> System.out.println(beanName + "-->" + bean));
        }
    

    控制台输入如下

    springMysqlDialect-->com.github.lybgeek.dialect.mysql.SpringMysqlDialect@73041b7d
    mysql-hello-->com.github.lybgeek.dialect.mysql.SpringMysqlDialect@574059d5
    springOracleDialect-->com.github.lybgeek.dialect.oracle.SpringOracleDialect@4a50d04a
    

    说明已经导入到spring容器中

    总结

    自从spring3+开始引入注解驱动后,在新项目基本上很少会使用xml,但如果是一些老旧的项目,大家如果想实现自定义标签注入到spring,就可以使用本文的方式。

    套路就是如下

    •   1、自定义xsd
    •   2、自定义解析BeanDefinitionParser解析器
    •   3、定义NamespaceHandler实现类处理自定义标签的处理器
    •   4、将写入处理器、标签的位置写入spring.handlers、spring.schemas中

    本文的实现也是相对简单,如果想深入使用,推荐看看dubbo自定义spring标签

    demo链接

    https://github.com/lyb-geek/springboot-learning/tree/master/springboot-spi-enhance/springboot-spi-framework-spring

  • 相关阅读:
    k8s记录-helm部署(九)
    k8s记录-master组件部署(八)
    Hadoop记录-Apache hadoop+spark集群部署
    k8s记录-ubuntu安装docker
    Nginx记录-Proxy_pass多个应用配置(转载)
    Java动态调用脚本语言Groovy
    05 吸收应用-会整理还不够?教你吸收、联想、输出、应用
    02 超级搜索术——资源搜索:全面、快速查找全网你想要的任何信息、情报
    01 超级搜索术——信息搜索:全面、快速查找全网你想要的任何信息、情报
    长赢指数基金投资计划-201807(一补仓)
  • 原文地址:https://www.cnblogs.com/linyb-geek/p/15576154.html
Copyright © 2011-2022 走看看