探索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/services和META-INF/seata中的实现类。代码里面可以找到很多参照spring的逻辑,加载的类也分为SINGLETON和PROTOTYPE,同样也是采用DefinitionHolder来进行类的初始化等。

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

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

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

相关推荐
IT_陈寒10 分钟前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
XW31 分钟前
常用提示词(Prompt)框架总结
后端
ServBay38 分钟前
DeepSeek 再次崩了,DeepSeek V5正在路上?
后端·deepseek
IT规划师1 小时前
编程术语中的同步与异步:从"等不等"到工程取舍
后端·面试
孟陬2 小时前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端
GoGeekBaird2 小时前
别再给每个 AI 做自我介绍了:我做了一个「个人上下文」管理系统
后端·github·agent
码事漫谈3 小时前
腾讯混元 Hy4 正式版发布了
后端
Mikko73 小时前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端
苍何4 小时前
DeepSeek的Super-agent 设计,和我们的工程实践
后端
Patrick_Wilson4 小时前
第一次读 Go 项目:从两个源码文件弄清 package、import 和 go.mod
后端·go·编程语言