当前位置: 首页 > 后端技术 > Java

说说自定义实现的SPI是如何与spring集成的

时间:2023-04-01 15:05:13 Java

前言上一篇主要讲了如何实现一个带有拦截器功能的SPI。今天就来说说自定义SPI是如何与spring结合的。思考:在我们实现的SPI中应该和spring集成哪些东西?或者我们应该利用spring的哪些特性来实现我们的东西呢?除了众所周知的IOC和AOP,spring还提供了丰富的扩展点,比如各种后处理器。今天我们就来说说一个大家比较熟悉的话题,自定义注解的使用方法。注入spring容器,整合思路1.自定义注解@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public@interfaceActivate{Stringvalue()default"";}2.自定义bean定义scannerpublicclassActivateClassPathBeanDefinitionScanner扩展ClassPathBeanDefinitionScanner{publicActivateClassPathBeanDefinitionScanner(BeanDefinitionRegistryregistry){super(registry);}@SneakyThrows@OverrideprotectedvoidregisterBeanDefinition(BeanDefinitionHolderdefinitionHolder,BeanDefinitionRegistryregistry){super.registerBeanDefinition(definitionHolder,registry);Classclz=Class.forName(definitionHolder.getBeanDefinition().getBeanClassName());激活activate=AnnotationUtils.findAnnotation(clz,Activate.class);如果(ObjectUtils.isNotEmpty(激活)&&StringUtils.isNotBlank(activate.value())){StringactivateName=getEnvironment().resolvePlaceholders(activate.value());registry.registerBeanDefinition(activateName,definitionHolder.getBeanDefinition());}}@OverrideprotectedbooleanisCandidateComponent(AnnotatedBeanDefinitionbeanDefinition){returnsuper.isCandidateComponent(beanDefinition)&&beanDefinition.getMetadata().hasAnnotation(Activate.class.getName());}3、定义ImportBeanDefinitionRegistrarpublicclassSpiRegisterimplementsImportBeanDefinitionRegistrar,EnvironmentAware{privateEnvironment环境;@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){SetbasePackages=this.getBasePackages(importingClassMetadata);字符串[]包={};SpiBeanUtils.registerActivateInstances(注册表,环境,basePackages.toAr射线(包));}4。自定义启用注释@Target(value=ElementType.TYPE)@Retention(value=RetentionPolicy.RUNTIME)@Documented@Import(SpiRegister.class)public@interfaceEnableSpi{String[]value()default{};String[]basePackages()默认{};Class[]basePackageClasses()default{};}实例演示1.在需要注入spring容器的类中添加@Activate注解@Activate("hello-mysql")publicclassSpringMysqlDialectimplementsSpringSqlDialect{@AutowiredprivateMysqlDialectServicemysqlDialectService;@OverridepublicStringdialect(){returnmysqlDialectService.dialect();}}2.在启动类中添加扫描SPI范围注解@SpringBootApplication(scanBasePackages="com.github.lybgeek")@EnableSpi(basePackages="com.github.lybgeek")publicclassSpiTestApplicationimplementsApplicationRunner3.使用getBeansOfType进行验证applicationContext.getBeansOfType(SpringSqlDialect.class).forEach((beanName,bean)->System.out.println(beanName+"-->"+bean));打印结果如下hello-mysql-->com.github.lybgeek.dialect.mysql.SpringMysqlDialect@433348bc表示已经注入spring容器。总结一下,将项目的服务托管到springioc容器中,可以看作是与spring集成的一个比较基础的动作。本文中的演示也是比较基础的部分,spring的强大之处在于它的扩展性。在springbean的生命周期中,随处可见扩展点。有兴趣的朋友可以体验验证demo链接https://github.com/lyb-geek/springboot-learning/tree/master/springboot-spi-enhance/springboot-spi-framework-spring