SPI 和 API 之间的区别?

2022-08-31 04:49:41

服务提供商接口 (SPI)应用程序编程接口 (API) 之间有什么区别?

更具体地说,对于Java库,是什么使它们成为API和/或SPI?


答案 1
  • API 是对类/接口/方法/...您打电话并使用来实现目标,以及
  • SPI是对类/接口/方法/...您扩展和实施以实现目标。

换句话说,API会告诉您特定类/方法对您执行的操作,而SPI会告诉您必须执行哪些操作才能符合要求。

通常 API 和 SPI 是分开的。例如,在 JDBC 中,Driver是 SPI 的一部分:如果您只想使用 JDBC,则不需要直接使用它,但实现 JDBC 驱动程序的每个人都必须实现该类。

然而,有时它们会重叠。连接接口既是 SPI 也是 API:当您使用 JDBC 驱动程序时,您可以定期使用它,并且需要由 JDBC 驱动程序的开发人员实现它。


答案 2

来自 Effective Java, 2nd Edition

服务提供者框架是一个系统,其中多个服务提供者实现一个服务,系统向其客户端提供实现,将它们与实现分离。

服务提供者框架有三个基本组成部分:服务接口,提供者实现;提供者注册API,系统使用它来注册实现,使客户端可以访问它们;和一个服务访问 API,客户端使用它来获取服务的实例。服务访问 API 通常允许但不要求客户端指定一些选择提供程序的条件。在没有此类规范的情况下,API 将返回默认实现的实例。服务访问 API 是构成服务提供程序框架基础的“灵活静态工厂”。

服务提供程序框架的可选第四个组件是服务提供程序接口,提供程序实现该接口以创建其服务实现的实例。在没有服务提供者接口的情况下,实现按类名注册并反射式实例化(项目 53)。在JDBC的情况下,连接扮演服务接口的角色,DriverManager.registerDriver是提供者注册API,DriverManager.getConnection是服务访问API,Driver是服务提供者接口。

服务提供程序框架模式有许多变体。例如,服务访问 API 可以使用适配器模式 [Gamma95,第 139 页] 返回比提供程序所需的服务接口更丰富的服务接口。下面是一个具有服务提供程序接口和默认提供程序的简单实现:

// Service provider framework sketch

// Service interface
public interface Service {
    ... // Service-specific methods go here
}

// Service provider interface
public interface Provider {
    Service newService();
}

// Noninstantiable class for service registration and access
public class Services {
    private Services() { }  // Prevents instantiation (Item 4)

    // Maps service names to services
    private static final Map<String, Provider> providers =
        new ConcurrentHashMap<String, Provider>();
    public static final String DEFAULT_PROVIDER_NAME = "<def>";

    // Provider registration API
    public static void registerDefaultProvider(Provider p) {
        registerProvider(DEFAULT_PROVIDER_NAME, p);
    }
    public static void registerProvider(String name, Provider p){
        providers.put(name, p);
    }

    // Service access API
    public static Service newInstance() {
        return newInstance(DEFAULT_PROVIDER_NAME);
    }
    public static Service newInstance(String name) {
        Provider p = providers.get(name);
        if (p == null)
            throw new IllegalArgumentException(
                "No provider registered with name: " + name);
        return p.newService();
    }
}

推荐