Java SPI机制

首先来说下 SPI 的全称: Service Provider Interface,直译过来就是“服务提供接口”。拆分出来就是 服务、提供、接口,三个词。

SPI不是一个框架,更不是一个具体实现,更偏向于是一种机制、规约。使用这种机制,遵循这种既定的规约,就可以提高系统的灵活性、可扩展性、模块化程度等。

他是干什么的呢???
查阅了相关资料,我来举两个例子哈

JDBC连接

JDBC 3.0 及之前的方式

在 JDBC 3.0 及之前,程序员需要显式地加载数据库驱动。这包括几个步骤:

手动加载数据库驱动类:使用 Class.forName() 方法加载数据库驱动类。这是必要的,因为数据库驱动不会自动被注册到 JDBC 驱动管理器中。

获取数据库连接:使用 DriverManager.getConnection() 方法获取连接。

下面是一个完整的例子:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseUtil {
    public static Connection getConnection() throws SQLException {
        // 手动加载数据库驱动
        try {
            Class.forName("com.mysql.jdbc.Driver"); // 旧版本的驱动类名
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new SQLException("Driver not found", e);
        }

        // 获取数据库连接
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "user";
        String password = "password";
        return DriverManager.getConnection(url, user, password);
    }
}

JDBC 4.0 及之后的方式

在 JDBC 4.0 及之后,Java 引入了服务提供者接口(SPI)机制,使得数据库驱动可以自动注册。这简化了数据库驱动的管理和加载过程。

不再需要手动加载驱动:驱动会通过 SPI 机制自动加载。你只需要确保 JDBC 驱动 JAR 文件在类路径中,并且该 JAR 文件包含 META-INF/services/java.sql.Driver 文件。

获取数据库连接:直接使用 DriverManager.getConnection() 方法获取连接,无需手动加载驱动。

下面是 JDBC 4.0 及之后的代码示例:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseUtil {
    public static Connection getConnection() throws SQLException {
        // 驱动会自动注册,无需手动加载
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "user";
        String password = "password";
        return DriverManager.getConnection(url, user, password);
    }
}

驱动 JAR 文件中的注册机制

为了使 JDBC 4.0 的自动注册机制生效,驱动 JAR 文件必须包含一个特定的文件:

META-INF/services/java.sql.Driver 文件
这个文件包含了驱动类的全限定名,例如:

com.mysql.cj.jdbc.Driver

当 Java 应用程序启动时,JDBC 驱动管理器会扫描所有类路径中的 JAR 文件,查找这个文件并加载列出的驱动类。这样,数据库驱动就会自动注册到 JDBC 驱动管理器中,无需程序员手动调用 Class.forName()

如果不是很清楚MySQL的驱动如何加载,可以查看MySQL驱动加载【底层实现】

案例二

Java 实用工具库(java.util.ServiceLoader)是 Java 提供的一种机制,用于动态加载服务提供者的实现。这种机制允许你在运行时发现和加载实现特定接口或抽象类的服务提供者,从而实现插件架构。ServiceLoader 是一个用来简化服务发现过程的工具。

假设你正在构建一个应用程序,支持多种不同的日志框架。你可以定义一个通用的日志接口,并让不同的日志框架实现这个接口,然后通过 ServiceLoader 动态加载这些实现。

  1. 第一步先定义一个日志接口

    public interface Logger {
        void log(String message);
    }
    
    
  2. 创建服务提供者的实现

    public class ConsoleLogger implements Logger {
        @Override
        public void log(String message) {
            System.out.println("Console: " + message);
        }
    }
    
    

    再创建一个实现类,用于生成文件

    import java.io.FileWriter;
    import java.io.IOException;
    
    public class FileLogger implements Logger {
        private FileWriter writer;
    
        public FileLogger() throws IOException {
            writer = new FileWriter("log.txt", true);
        }
    
        @Override
        public void log(String message) {
            try {
                writer.write(message + System.lineSeparator());
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
  3. 在服务提供者 JAR 文件中注册服务

    在每个实现的 JAR 文件中,创建一个文件 META-INF/services/com.example.Logger。这个文件的内容是服务接口的实现类的全限定名。例如:

    com.example.ConsoleLogger
    com.example.FileLogger
    

    这个文件使得 ServiceLoader 能够发现并加载这些实现类。

  4. 使用 ServiceLoader 加载服务实现

    import java.util.ServiceLoader;
    
    public class LoggerFactory {
        public static void main(String[] args) {
            ServiceLoader<Logger> loader = ServiceLoader.load(Logger.class);
    
            for (Logger logger : loader) {
                logger.log("Hello, SPI!");
            }
        }
    }
    
    

按照以上例子,大概已经明白了个所以然。

接着我看了一些视频和评论,分享如下👇

posted @   DAawson  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示