前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊自定义实现的SPI如何与spring进行整合

聊聊自定义实现的SPI如何与spring进行整合

原创
作者头像
lyb-geek
修改2021-11-09 10:31:34
4960
修改2021-11-09 10:31:34
举报
文章被收录于专栏:Linyb极客之路

前言

上一篇文章主要聊聊如何实现一个带有拦截器功能的SPI。今天就来聊聊自定义的SPI如何与spring整合。

思考:我们实现的SPI要整合spring哪些东西?或者我们要利用spring的哪些特性实现我们哪些东西?

spring除了被大家熟知的IOC和AOP之外,还有它也提供了很丰富的扩展点,比如各种后置处理器,今天我们就聊聊大家相对熟悉的话题,如何通过自定义注解把SPI注入到spring容器中

整合思路

1、自定义注解

代码语言:txt
复制
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Activate {

    String value() default "";
}

2、自定义bean定义扫描器

代码语言:txt
复制
public class ActivateClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {


    public ActivateClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }


    @SneakyThrows
    @Override
    protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
        super.registerBeanDefinition(definitionHolder, registry);
        Class clz = Class.forName(definitionHolder.getBeanDefinition().getBeanClassName());
        Activate activate = AnnotationUtils.findAnnotation(clz,Activate.class);
        if(ObjectUtils.isNotEmpty(activate) && StringUtils.isNotBlank(activate.value())){
            String activateName = getEnvironment().resolvePlaceholders(activate.value());
            registry.registerBeanDefinition(activateName,definitionHolder.getBeanDefinition());
        }
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return super.isCandidateComponent(beanDefinition) && beanDefinition.getMetadata()
                .hasAnnotation(Activate.class.getName());
    }

3、定义ImportBeanDefinitionRegistrar

代码语言:txt
复制
public class SpiRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Environment environment;


    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        Set<String> basePackages = this.getBasePackages(importingClassMetadata);
        String[] packages = {};
        SpiBeanUtils.registerActivateInstances(registry,environment,basePackages.toArray(packages));
    }

4、自定义enabled注解

代码语言:txt
复制
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Import(SpiRegister.class)
public @interface EnableSpi {

  
    String[] value() default {};

 
    String[] basePackages() default {};

  
    Class<?>[] basePackageClasses() default {};
}

示例演示

1、在需要注入到spring容器的类上加上@Activate注解

代码语言:txt
复制
@Activate("hello-mysql")
public class SpringMysqlDialect implements SpringSqlDialect {

    @Autowired
    private MysqlDialectService mysqlDialectService;

    @Override
    public String dialect() {
        return mysqlDialectService.dialect();
    }


}

2、启动类上加上扫描SPI范围注解

代码语言:txt
复制
@SpringBootApplication(scanBasePackages = "com.github.lybgeek")
@EnableSpi(basePackages = "com.github.lybgeek")
public class SpiTestApplication implements ApplicationRunner 

3、利用getBeansOfType进行验证

代码语言:txt
复制
 applicationContext.getBeansOfType(SpringSqlDialect.class)
                .forEach((beanName,bean) -> System.out.println(beanName + "-->" + bean));

打印结果如下

代码语言:txt
复制
hello-mysql-->com.github.lybgeek.dialect.mysql.SpringMysqlDialect@433348bc

说明已经注入到spring容器中

总结

把项目的服务托管给spring ioc容器,可以算是与spring整合比较基础的动作,本文演示也是相对基础的一环,spring 强大的地方,在于它的扩展性,在spring bean的生命周期中,基本上随处可见扩展点,感兴趣的朋友后续可以自行体会验证

demo链接

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 整合思路
    • 1、自定义注解
      • 2、自定义bean定义扫描器
        • 3、定义ImportBeanDefinitionRegistrar
          • 4、自定义enabled注解
          • 示例演示
          • 总结
          • demo链接
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档