Browse Source

doc:添加readme文档

yang yi 1 month ago
parent
commit
5ef81728c1
1 changed files with 266 additions and 0 deletions
  1. 266 0
      readme.md

+ 266 - 0
readme.md

@@ -0,0 +1,266 @@
+# java SPI机制
+
+[参考bilibili的视频](https://www.bilibili.com/video/BV1RY4y1v7mN/)
+
+Service Provider Interface
+
+java1.6引入的,基于ClassLoader的**发现并加载服务**的机制
+
+## 核心概念
+
+- Service:提供服务的接口,服务的标准
+- Service Provider:服务的具体实现,服务的提供者
+- Service Loader:服务的加载器,通过Server Loader加载具体的服务实现
+
+## SPI的工作机制
+
+JDBC技术典型的SPI实践案例,JDK通过Service接口,具体的数据库厂商负责具体的Service Provider实现
+
+1. 应用程序启动时通过Service Loader加载第三方jar中的Service Provider(Service的具体实现类)
+2. 在应用程序中通过Service的形式使用,不用关心具体的实现细节
+
+## SPI规范
+
+1. 配置文件规范
+
+    - 文件路径:必须在jar包中META-INF/services目录下
+    - 文件名称:Service接口的全限定名
+    - 文件内容:Service Provider实现类的全限定名,每个实现类单独占一行
+
+   >e.g
+   >
+   >在MySQL的驱动jar中的META-INF/services目录中有一个"java.sql.Driver"文件,文件内容为"com.mysql.cj.jdbc.Driver"
+
+2. Service Provide类必须具备无参的构造方法
+
+    - 因为使用反射技术创建实现类时需要使用无参构造器
+
+3. 保证能加载到配置文件和Service
+
+    - 方式一:将Service Provider的jar包放到classpath中
+    - 方式二:将jar放到jre的扩展目录中
+    - 方式三:自定义一个ClassLoader
+
+## SPI实现案例
+
+一个公司A,需要连接互联网.公司A定义连接网络的API(Service),由中国移动(Service Provider)和中国联通(Serivce Provider)负责提供具体的网络连接服务
+
+>SPI实现流程
+>
+>1. 在service定义接口
+>2. 在service provider中实现service,并在META-INF/services目录下提供对应的配置文件
+>3. 在应用程序中使用ServiceLoader加载service,然后进行使用
+
+### 定义service接口
+
+1. 定义service接口
+    - 在模块Simple-api中定义网络的连接接口
+
+```java
+package space.anyi;
+
+/**
+ * @ProjectName: SPI-learn
+ * @FileName: InternetService
+ * @Author: 杨逸
+ * @Data:2025/10/13 11:13
+ * @Description: 网络服务接口
+ */
+public interface InternetService {
+    void connect();
+}
+
+```
+
+### Service Provider实现Service接口
+
+1. 模块simple-isp-moblie
+    - 模块simple-isp-moblie引入simple-api依赖
+
+```groovy
+plugins {
+    id 'java'
+}
+
+group 'space.anyi'
+version '1.0-SNAPSHOT'
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    //引入simple-api依赖,以项目的形式
+    implementation(project(":simple-api"))
+    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
+    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
+}
+
+test {
+    useJUnitPlatform()
+}
+
+```
+
+- 模块simple-isp-moblie实现service
+
+```java
+package space.anyi;
+
+/**
+ * @ProjectName: SPI-learn
+ * @FileName: MoblieInternetService
+ * @Author: 杨逸
+ * @Data:2025/10/13 11:24
+ * @Description: 中国移动提供的网络服务实现
+ */
+public class MoblieInternetService implements InternetService{
+
+    @Override
+    public void connect() {
+        System.out.println("使用中国移动提供的网络服务");
+    }
+}
+
+```
+
+- 在"META-INF/services"目录下提供"space.anyi.InternetService"配置文件
+
+```tex
+space.anyi.MoblieInternetService
+```
+
+2. 模块simple-isp-unicom
+
+- 模块simple-isp-unicom引入simple-api依赖
+
+  ```groovy
+  plugins {
+      id 'java'
+  }
+  
+  group 'space.anyi'
+  version '1.0-SNAPSHOT'
+  
+  repositories {
+      mavenCentral()
+  }
+  
+  dependencies {
+      //引入simple-api依赖,以项目的形式
+      implementation(project(":simple-api"))
+      testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
+      testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
+  }
+  
+  test {
+      useJUnitPlatform()
+  }
+  
+  ```
+
+
+
+- 模块simple-isp-unicom实现service
+
+```java
+package space.anyi;
+
+/**
+ * @ProjectName: SPI-learn
+ * @FileName: UnicomInternetService
+ * @Author: 杨逸
+ * @Data:2025/10/13 11:37
+ * @Description: 中国联通提供的网络服务实现
+ */
+public class UnicomInternetService implements InternetService{
+    @Override
+    public void connect() {
+        System.out.println("使用中国联通提供的网络服务");
+    }
+}
+
+```
+
+在"META-INF/services"目录下提供"space.anyi.InternetService"配置文件
+
+```tex
+space.anyi.UnicomInternetService
+```
+
+### Service Loader加载Service
+
+- 模块simple-compnay引入依赖
+
+  ```groovy
+  plugins {
+      id 'java'
+  }
+  
+  group 'space.anyi'
+  version '1.0-SNAPSHOT'
+  
+  repositories {
+      mavenCentral()
+  }
+  
+  dependencies {
+      //可以全都使用,也可以按需使用
+      //服务提供,使用中国移动的网络服务
+      implementation(project(":simple-isp-moblie"))
+      //服务提供,使用中国联通的网络服务
+      implementation(project(":simple-isp-unicom"))
+      //接口依赖
+      implementation(project(":simple-api"))
+      testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
+      testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
+  }
+  
+  test {
+      useJUnitPlatform()
+  }
+  
+  ```
+
+
+
+- 使用加载Service并使用
+
+  ```java
+  package space.anyi;
+  
+  import java.util.ServiceLoader;
+  
+  /**
+   * @ProjectName: SPI-learn
+   * @FileName: CompanyApplication
+   * @Author: 杨逸
+   * @Data:2025/10/13 11:45
+   * @Description: 公司A连接互联网的应用
+   */
+  public class CompanyApplication {
+      public static void main(String[] args) {
+          //通过java.util.ServiceLoader加载服务
+          ServiceLoader<InternetService> services = ServiceLoader.load(InternetService.class);
+          //遍历服务
+          for (InternetService service : services) {
+              //使用服务
+              service.connect();
+          }
+  
+      }
+  }
+  
+  ```
+
+  运行项目实现开箱即用的效果
+
+  ![](http://tuchuang.anyi.space/imgs/Snipaste_2025-10-13_13-59-04.png)
+
+## SPI总结
+
+- 作用:提供了一种组件发现和注册的方式,可以用于实现各种插件,或者灵活替换框架使用的组件
+- 优点:基于面向接口编程,优雅地实现模块之间的解藕
+- 设计思想:面向接口+配置文件+反射技术
+- 应用场景:JDBC,SLF4J,Servlet容器初始化等等
+