前言
上一篇文章次要聊聊如何实现一个带有拦截器性能的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