java热插拔组件 SPI机制


前言

在项目中,如果想要增加项目的灵活性,健壮性, 高逼格,那么你要对于java中的一些机制有了解;
例如:

  • java中的spi机制
  • spring中的spring.factories 等

这里重点说明spi机制,其实 spring中的spring.factories文件与spi机制类似,这里给大家留个小作业,去自己看吧~


一、热插拔(spi机制)是什么?

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制,可以轻松实现面向服务的注册与发现,完成服务提供与使用的解耦,并且可以实现动态加载。
  引入服务提供者就是引入了SPI接口的实现者,通过本地的注册发现获取到具体的实现类,轻松可插拔,SPI实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载,为某个接口寻找服务实现的机制。

说人话就是:

通过它可以实现 某个接口的策略灵活选择一个实现类,并且可以利用更改配置文件,或者选择内容的机制(甚至通过程序改变), 无需重启服务,即可切换实现类,完成 “热插拔”,像使用一些组件一样,灵活添加,卸载掉 功能实现类;

以程序中常见的, 策略模式为例:

  1. 登录接口
  2. 登录接口实现类: 手机登录(1) 用户名密码登录(2) 邮箱登录(3)
  3. 项目中三个实现类都有,多个环境部署给不同用户, 要求如下
  4. A 环境采用 1 2 登录, B环境采用 2 登录, C 环境采用 23 登录 ,D 环境采用 123 登录

展示吧~~ 咋弄吧? 一个环境一个环境的改代码? 把多余的实现类删掉?
这里就可以通过spi机制,灵活的配置每个环境的实现类,达到上述要求

二、使用步骤

1.利用java META-INF

  1. 创建接口
// 接口
public interface SpiService {
    
    
    void sout();
}
  1. 创建实现类
// 实现类
public class SpiServiceImpl implements SpiService {
    @Override
    public void sout() {
        System.out.println("SpiServiceImpl 被调用");
    }
}
  1. 在resource文件夹下创建文件夹(META-INF.services)以及文件
    • 文件名称 接口全路径 : com.pdf.word.service.SpiService
    • 文件内容 接口实现类全路径 : com.pdf.word.service.impl.SpiServiceImpl
      文件夹以及文件

2.利用google spi

  1. 创建接口
public interface GoogleSpiService {
    void sout();
}
  1. 创建实现类
  2. 引入google,在实现类上加入@AutoService(接口.class)
@AutoService(GoogleSpiService.class)
public class GoogleSpiServiceImpl implements GoogleSpiService {
    @Override
    public void sout() {
        System.out.println("GoogleSpiService 被调用");
    }
}

3. 测试效果

创建一个测试类

class SpiServiceTest {

    public static void main(String[] args) {
        /**---------------------------利用java META-INF ----------------------------------------**/
        ServiceLoader<SpiService> load = ServiceLoader.load(SpiService.class);
        List<SpiService> spiServiceList = load.stream().map(ServiceLoader.Provider::get).toList();
        for (SpiService spiService : spiServiceList) {
            spiService.sout();
        }
        /**---------------------------利用google spi ----------------------------------------**/
        ServiceLoader<GoogleSpiService> load1 = ServiceLoader.load(GoogleSpiService.class);
        List<GoogleSpiService> spiServiceList1 = load1.stream().map(ServiceLoader.Provider::get).toList();
        for (GoogleSpiService spiService : spiServiceList1) {
            spiService.sout();
        }
    }

}

运行后,打印如下:
运行结果

总结

通过两种方式都可以实现spi机制的调用,这里展示简单调用,当项目中有多个实现类的时候,就可以灵活多变的实现热插拔效果了~

  • 利用java META-INF
    想用哪个,哪些实现类,就在文件中写哪些实现类的类全路径,每个实现类独占一行
  • 利用google spi
    想用哪个,哪些实现类,就在相应的实现类上加注解就行了

猜你喜欢

转载自blog.csdn.net/qq_32419139/article/details/132018610