参考
一篇文章搞明白Java中的SPI机制
可插拔组件设计机制—SPI
Spring.factories
通过S3协议实现通用的文件存储服务中间件
一、SPI机制
1、什么是SPI
SPI 的全称是Service Provider Interface,即提供服务接口;是一种服务发现机制,SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。
通过多模块分布式文件存储edevp-dfs展示SPI机制
2、使用场景?
数据库驱动加载接口实现类的加载;如:JDBC 加载Mysql,Oracle…
日志门面接口实现类加载,如:SLF4J 对log4j、logback 的支持
Spring中大量使用了SPI,特别是spring-boot 中自动化配置的实现
Dubbo 也是大量使用SPI 的方式实现框架的扩展,它是对原生的SPI 做了封装,允许用户扩展实现Filter 接口。
3、使用介绍
要使用 Java SPI,需要遵循以下约定:
当服务提供者提供了接口的一种具体实现后,需要在JAR 包的META-INF/services 目录下创建一个以“接口全限制定名”为命名的文件,内容为实现类的全限定名;
接口实现类所在的JAR放在主程序的classpath 下,也就是引入依赖。
主程序通过java.util.ServiceLoder 动态加载实现模块,它会通过扫描META-INF/services 目录下的文件找到实现类的全限定名,把类加载值JVM,并实例化它;
SPI 的实现类必须携带一个不带参数的构造方法。
示例:
4、代码演示
新建工程edevp-dfs-api的spi接口
package com.edevp.dfs.api;
/**
* @create 2023-04-11
*/
public interface DfsService {
/**
* 创建bucket
* @param bucketName 存储桶
*/
void createBucket(String bucketName);
/**
* 判断存储桶是否存在
* @param bucketName 存储桶
*/
default boolean doesBucketExist(String bucketName){
return true;}
/**
* 初始化
*/
void init();
}
新建阿里云oss实现类
public class OssServiceImpl implements DfsService {
@Override
public void createBucket(String bucketName) {
if (!amazonS3.doesBucketExistV2(bucketName)) {
amazonS3.createBucket((bucketName));
}
}
public boolean doesBucketExist(String bucketName){
return enable && amazonS3.doesBucketExistV2(bucketName);
}
@PostConstruct
@Override
public void init() {
System.out.println("oss");
}
在resource下新建/META-INF/services/com.edevp.dfs.api.DfsService
的文件,内容如下:
com.edevp.dfs.impl.OssServiceImpl