API 和 SPI

Posted 思想累积

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了API 和 SPI相关的知识,希望对你有一定的参考价值。

1、什么是 API 和 SPI

API(Application Programming Interface)

大多数情况下,都是实现方来制定接口并完成对接口的不同实现,调用方仅仅依赖并直接进行使用却无权选择不同实现。

SPI(Service Provider Interface)

SPI 是JDK 提供的一种服务提供发现机制, 调用方来制定接口,实现方来针对接口来进行不同的实现。调用方来选择自己需要的实现方。

在这里插入图片描述

2、API 和 SPI 用途

API 用途:

API 可以理解为服务方暴露自己的服务供客户调用,JDK 就作为服务方,提供了一系列的 api 可以直接使用的方法供客户方开发人员直接进行使用,从而达到某种功能的实现

SPI 用途

SPI 是服务方不再提供具体的方法,而是提供对象的接口,客户方需要实现接口,然后服务方调用客户方的接口实现类,再来实现客户的某种功能。

在 JDBC 连接数据库时,针对不同的数据库,可能有不同的数据库驱动实现。不同数据库的 Driver 驱动通过 DriverManager 来进行管理,我们在使用 Class.forName("driverName") 加载驱动时,就会执行其中的静态代码块,将 Driver 注册到 DriverManager 中供后面进行使用。

Java 中定义了 java.sql.Driver 接口,并没有具体的实现,具体实现由各厂商来提供,通过厂商提供的驱动包来连接自己的数据库。

在这里插入图片描述
3、SPI 应用实例

当服务的提供者提供了一种借口的实现后,需要在 classpath 下的 META-INF/services 目录里创建一个以服务接口命名的文件,这个文件内容就是接口的具体实现类。

其它程序需要调用这个服务的时候,可以查找这个下面的配置文件,根据这个文件中的类名加载实例化,就可以使用该服务了

String url = "jdbc:mysql://localhost:3306/test";
Connection conn = DriverManager.getConnection(url,username,password);

在上述代码中没有加载驱动,我们怎么确定使用的是哪个数据库连接的驱动呢?

在 DriverManager 中有一个静态方法

static {
	loadInitialDrivers();
	println("JDBC DriverManager initialized");
}

这个 loadInitialDrivers 方法使用了SPI 工具类 ServiceLoader
在这个方法中会搜索 classpath 下所有 META-INF/service 目录下的 java.sql.Driver 文件,并找到文件中实现类的名字

AccessController.doPrivileged(new PrivilegedAction<Void>() {
    public Void run() {
        ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
        Iterator<Driver> driversIterator = loadedDrivers.iterator();

        /* Load these drivers, so that they can be instantiated.
         * It may be the case that the driver class may not be there
         * i.e. there may be a packaged driver with the service class
         * as implementation of java.sql.Driver but the actual class
         * may be missing. In that case a java.util.ServiceConfigurationError
         * will be thrown at runtime by the VM trying to locate
         * and load the service.
         *
         * Adding a try catch block to catch those runtime errors
         * if driver not available in classpath but it's
         * packaged as service and that service is there in classpath.
         */
        try{
            while(driversIterator.hasNext()) {
                driversIterator.next();
            }
        } catch(Throwable t) {
        // Do nothing
        }
        return null;
    }
});

以上是关于API 和 SPI的主要内容,如果未能解决你的问题,请参考以下文章

API 和 SPI

Java SPI 和 API,傻傻分不清?

Java SPI 源码解析

Regmap API 实验

STM32H7的SPI总线基础知识和HAL库API

java-spi