探索SpringBoot和Seata中的SPI机制实现

本文章主要想了解一下SpringBoot,Seata组件中都是怎么使用SPI功能。如何调用SPI的接口实现类,能够提供哪些便利。

SPI (Service Provider Interface) -- 接口服务发现机制

Spring SPI

SpringBoot中最方便的功能莫过于自动配置功能,只需要集成一个Starter的jar包。基本不需要配置就可以实现数据库调用,远程调用,服务配置,服务发现等功能。Spring其实也是使用自己实现的SPI机制来进行的初始化加载并自动配置。

源码解析

Spring的加载都是通过调用SpringApplication.run来进行处理的。追踪一下这个注解,通过run方法可以很容易找到入口操作的地方。

这里就是部分的SPI入口,可以得知是加载了两个接口实现类,分别为ApplicationContextInitializer(应用上下文初始化类),ApplicationListener(应用监听类)

分为两步,第一步获取所有需要加载的SPI的全限定名称(使用Set来进行去重)。第二步利用BeanUtils.instantiateClass方法实例化这些对象。

获取需要加载的类

追踪后重点看一下这个箭头这里加载的路径,从资源路径加载和从系统路径加载。路径值为

这里就可以得到所有的SPI类都会放到上述路径中供spring加载。这里其实可以延伸一个问题,刚才只是加载了两个接口的类,Spring也实现其他接口的类。上面可以看到有一个8 usages,这里就可以知道调用的地方其实很多,对应其他的SPI实现接口类的加载。

ApplicationContextInitializer 应用上下文初始化类
ApplicationListener 应用监听类
SpringApplicationRunListener Spring应用执行监听
EnableAutoConfiguration(注解) 大部分自动配置类(invokeBeanFactoryPostProcessors(beanFactory);)
AutoConfigurationImportFilter 自动配置过滤类
AutoConfigurationImportListener 自动配置监听类
EnvironmentPostProcessor 环境变量执行器类
PropertySourceLoader 属性加载器

加粗的是比较常用的接口加载类,当需要使用对应功能时,直接在自己的Jar包中实现对应的接口,并配置到META-INF/spring.factories中即可。spring就可以读到对应的配置了。

常见用例

打开Mybatis Starter中的META-INF/spring.factories,可以看到

这里有一个概念需要强化一下,类上面添加了注解Configuration的类就不是一个普通的spring bean,具备了一定的配置功能。由ConfigurationClassParser中的parse方法来进行处理。类似于以前spring的一个xml文件,可以加载很多的bean。查看mybatis的配置类可以知道mybatis初始化了sqlSessionFactory,sqlSessionTemplate,spring相应的会自动配置这些bean到容器中。

Seata SPI

照例打开META-INF文件可以看到

在services文件夹下有多个文件,文件名称代表接口名称,文件内容是代表接口的多个实现。搜索全局代码后找到入口类时EnhancedServiceLoader(增强服务加载类)。核心的逻辑在内部类InnerEnhancedServiceLoader中。相应的也是有缓存机制,如果已经加载的类直接后去,SEATA的这个SPI使用静态方法实现,比较容易接入系统。

接着往下找,加载路径类的逻辑写在findAllExtensionDefinition中,分别加载了META-INF/servicesMETA-INF/seata中的实现类。代码里面可以找到很多参照spring的逻辑,加载的类也分为SINGLETONPROTOTYPE,同样也是采用DefinitionHolder来进行类的初始化等。

类的对象创建是在getExtensionInstance中实现,利用构造器创建的对象。整体看下来seata的SPI适配性更好,使用静态方法加载,且支持对象列表返回。

可以看到调用的地方是直接调用静态方法,传入想要的方法即可。

其实综合上面两种SPI机制,可以知道SPI是为扩展准备的,当需要适配不同类型的插件,且需要动态加载时。就可以采用SPI机制来进行加载自实现的接口实现类。

相关推荐
烂蜻蜓1 小时前
Flask入门教程(二十六):Session API——用户会话状态管理
后端·python·flask
郑州光合科技余经理3 小时前
本地生活服务系统:成品模块和定制接口怎么划界
java·前端·人工智能·后端·系统架构·php·ai编程
朦胧之9 小时前
PostgreSQL 数据库笔记
人工智能·后端
user_admin_god10 小时前
数据采集/交换系统设计经验
spring boot·spring·策略模式
IT_陈寒11 小时前
Redis缓存雪崩把我坑惨了,这次长记性了
前端·人工智能·后端
LucianaiB12 小时前
用 WorkBuddy 研究腾讯、阿里和 DeepSeek,我没敢直接说「AI 很赚钱」
后端
用户83562907805112 小时前
使用 Python 管理 PDF 属性和元数据
后端·python
分支预测失败12 小时前
RISC-V 上下文切换实战:从 Trap 入口到 Linux 进程调度
后端·嵌入式
学代码的CJY12 小时前
Linux 重定向、管道与环境变量
linux·spring boot·spring
用户83562907805113 小时前
使用 Python 在 Word 文档中创建自定义图表
后端·python