API 和 SPI

本文探讨了API(Application Programming Interface)和SPI(ServiceProvider Interface)的区别,包括API由服务提供方制定接口,而SPI则由调用方指定接口。SPI的应用实例涉及JDBC数据库驱动的选择和自动注册过程。
摘要由CSDN通过智能技术生成

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;
    }
});
  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一起来搬砖呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值