java Spi、springSpi、dubboSpi
1、Java SPI(Service Provider Interface)一种服务发现机制
它允许服务提供者实现服务接口,并将其实现放置在 JAR 文件中,使得服务消费者可以在运行时动态加载和使用这些实现。Java SPI 主要通过配置文件 META-INF/services/
实现,配置文件中列出服务接口实现类的全限定名。
Java SPI 示例
假设我们有一个服务接口 Robot
,和两个实现类 OptimusPrime
和 Bumblebee
:
public interface Robot {
void run();
}
public class OptimusPrime implements Robot {
@Override
public void run() {
System.out.println("Run on the ground");
}
}
public class Bumblebee implements Robot {
@Override
public void run() {
System.out.println("Run in the water");
}
}
在 META-INF/services/
目录下创建一个文件,文件名为 Robot
的全限定名,内容为实现类的全限定名:
在运行时,可以使用 ServiceLoader
动态加载服务实现:
ServiceLoader<Robot
> loader = ServiceLoader.load(Robot
.class) ;
Iterator<Robot
> iterator = loader.iterator();
while(iterator.hasNext()){
//顺序读取实现类
}
缺点:
①、不能按需加载(可以解决:重新实现它读取加载文件的方式,在内存建立索引,以此来实现快速动态获取指定实现并加载,同时监听文件修改内容,同步刷新内存,这是基于内存式设计,或者基于文件扫描来获取
)
②、获取某个实现类的方式不够灵活,只能通过Iterator方式获取
③、并发多线程使用ServiceLoader类的实例不安全
2、spring Spi
springSpi沿用javaspi的设计思想,采用的是‘spring.factories’方式实现spi机制,可以在不修改spring源码的前提下,提高spring框架的扩展性 。
调用SpringFactoriesLoader.loadFactories()方法加载接口所有实现类的实例
List<TestService> list = SpringFactoriesLoader.loadFactories(
TestService.class,Thread.currentThread().getContextClassLoader() )
Spring SPI 是一个spring.factories 配置文件存放多个接口及对应的实现类,以接口全限定名作为key,实现类作为value来配置,多个实现类用逗号隔开,仅`spring.factories`一个配置文件。
和 Java SPI 一样,Spring SPI 也无法获取某个固定的实现,只能按顺序获取所有实现。
(spring特殊实现按需加载: ApplicationContext context = new AnnotationConfigApplicationContext();
// 根据条件选择特定的实现类
DataProcessingService selectedService = context.getBean("cn.infinite.cascade.partial.service.api.PartialCircuitCascadeServiceImpl", DataProcessingService.class);
if (selectedService != null) {
selectedService.processData(); }
)
3、Dubbo SPI
Dubbo SPI 是一种更为灵活的服务扩展机制,基于 Java SPI的缺陷无法支持按需加载接口实现类,Dubbo 并未使用Java SPI, 而是重新实现了一套功能更强的 SPI 机制,包括自动注入、AOP 拦截器、适配器等。
Dubbo SPI的相关逻辑被封装在了 ExtensionLoader 类中,通过ExtensionLoader,我们可以加载指定的实现类。
Dubbo SPI所需的配置文件需放置在`META-INF/dubbo`路径下,配置内容如下:与 Java SPI实现类配置不同,Dubbo SPI是通过键值对的方式进行配置,这样我们可以按需加载指定的实现类。
另外,在测试 Dubbo SPI时,需要在 Robot 接口上标注 @SPI 注解。
@SPI
public interface Robot {
void run();
}
public class OptimusPrime implements Robot {
@Override
public void run() {
System.out.println("Run on the ground");
}
}
public class Bumblebee implements Robot {
@Override
public void run() {
System.out.println("Run in the water");
}
}
在运行时,可以使用 Dubbo 的扩展加载机制动态加载服务实现:
ExtensionLoader<Robot> loader = ExtensionLoader.getExtensionLoader(Robot.class);
Robor optimusPrime = loader.getExtension(optimusPrime);
Robor bumblebee= loader.getExtension(bumblebee);
这些 SPI 机制提供了灵活的扩展点和服务发现机制,能够在不同场景下满足不同的需求。
Java SPI 适用于静态的服务加载,Spring SPI 适用于 Spring 容器的生命周期扩展,而 Dubbo SPI 则提供了更加灵活和强大的服务扩展机制