前言

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

思考:咱们实现的SPI要整合spring哪些货色?或者咱们要利用spring的哪些个性实现咱们哪些货色?

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

整合思路

1、自定义注解

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Activate {    String value() default "";}

2、自定义bean定义扫描器

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

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注解

@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注解
@Activate("hello-mysql")public class SpringMysqlDialect implements SpringSqlDialect {    @Autowired    private MysqlDialectService mysqlDialectService;    @Override    public String dialect() {        return mysqlDialectService.dialect();    }}
2、启动类上加上扫描SPI范畴注解
@SpringBootApplication(scanBasePackages = "com.github.lybgeek")@EnableSpi(basePackages = "com.github.lybgeek")public class SpiTestApplication implements ApplicationRunner 
3、利用getBeansOfType进行验证
 applicationContext.getBeansOfType(SpringSqlDialect.class)                .forEach((beanName,bean) -> System.out.println(beanName + "-->" + bean));

打印后果如下

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