实现一个spring boot starter(一)——SPI机制

发布时间 2023-08-13 22:24:09作者: leo_space

你好,我是leo,spring boot的starter给应用的配置带来了很多方便,它可以轻松地添加某个特定的功能到我们的应用,而不用手动配置大量的依赖项和默认值。在这个文章系列里,leo就来聊聊starter这个话题。

一:SPI机制
二:手写一个简易的starter
三:自动装配功能扩展

首先,在这篇文章里,leo要简述一下java和spring的SPI机制,这是理解starter的基础。

什么是java的SPI

java的SPI(Service Provider Interface)机制是一种用于实现模块化、可插拔式架构的设计模式。它允许开发人员在不修改代码的情况下,通过在classpath中添加外部的实现来扩展应用程序的功能。

怎么理解呢?其实用大白话说,就是java内置了一种服务发现模式,比如我是一个服务调用者,我先定义好一个接口,这个接口要实现某种功能,我在我自己的应用中只管调用接口,不关注接口的实现。谁来实现呢?用我程序的人来实现。

用的人自己实现?没错。你可能会说,这么麻烦那我不用了。但是往往能用SPI机制定义接口的一方,都是底层的框架,很难选择不用。比如jdk中定义的数据库接口java.sql.driver,比如日志门面框架slf4j定义的接口org.slf4j.spi.SLF4JServiceProvider(2.0.0以上版本)

当然,底层框架框架定义的SPI接口,也会贴心地给默认实现,不会只定义一个接口就不管了。还是拿日志框架来举例,slf4j的作者本人写的日志组件logback,就实现了slf4j的SPI接口

SPI解决了什么问题?

SPI机制解决了软件开发中的灵活性、可扩展性、松耦合性和模块化等问题。

  • 灵活可扩展性
    SPI允许服务提供方给SPI接口添加新的实现,并且无需修改服务调用方现有的代码,从而轻松地扩展程序的功能。
  • 松耦合
    SPI机制通过接口和实现的分离,实现了松耦合的设计。框架层面只需要依赖于接口,而不需要关心具体的实现。
  • 插件化架构
    SPI允许开发人员在程序运行时动态地加载外部实现,可以根据需求添加或移除特定的功能模块。

SPI是如何实现的?

SPI机制的核心是ServiceLoader类,还是拿上面举例的slf4j和logback来说明吧
1.首先在slf4j定义一个接口SLF4JServiceProvider,接口的全名是org.slf4j.spi.SLF4JServiceProvider
2.然后在logback中提供该接口的实现类LogbackServiceProvider
3.接着在logback的META-INF/services目录下增加一个文件,文件名是org.slf4j.spi.SLF4JServiceProvider,必须和接口的全名一致。文件的内容是ch.qos.logback.classic.spi.LogbackServiceProvider,也就是实现类的全名
image

4.最后在slf4j的LoggerFactory中用ServiceLoader.load方法加载具体的实现类
image

好,leo来总结一下,步骤是:框架中定义接口,组件实现接口,并且把接口类名和实现类名配置在META-INF/services目录下,最后框架用ServiceLoader.load方法加载实现类

SPI机制的缺点是什么?

SPI机制在程序启动时加载配置文件并实例化服务提供者,这是一种静态加载机制,无法支持在运行时动态更改服务提供者

另外,当一个SPI接口同时提供了多个实现时,ServiceLoader会实例化所有的实现类,即使只获取其中某一个实现,也要通过迭代器遍历所有的实现。

spring的SPI机制和java原生的SPI机制有什么不同?

其实spring的SPI机制在实现上和java原生的SPI很相似,只不过配置文件的路径变成了META-INF/spring.factories,实现加载功能的类变成了SpringFactoriesLoader。

另外在配置文件的写法上有所不同:java的SPI要求一个接口对应一个配置文件,而spring的SPI要求所有的接口名和实现类名都写到一个配置文件

结语

好了,到这里为止就是leo对java SPI机制的所有理解了,下一篇文章,leo会写一个spring boot starter的例子,来进一步说明starter


参考资料:

《java SPI详解》https://blog.csdn.net/Q54665642ljf/article/details/127610418
《深入剖析 Spring Boot 的 SPI 机制》
https://cloud.tencent.com/developer/article/2277222