2024-01-04 05:00:02

SPI和API的区别?

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

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


当前回答

摘自Effective Java,第二版:

A service provider framework is a system in which multiple service providers implement a service, and the system makes the implementations available to its clients, decoupling them from the implementations. There are three essential components of a service provider framework: a service interface, which providers implement; a provider registration API, which the system uses to register implementations, giving clients access to them; and a service access API, which clients use to obtain an instance of the service. The service access API typically allows but does not require the client to specify some criteria for choosing a provider. In the absence of such a specification, the API returns an instance of a default implementation. The service access API is the “flexible static factory” that forms the basis of the service provider framework. An optional fourth component of a service provider framework is a service provider interface, which providers implement to create instances of their service implementation. In the absence of a service provider interface, implementations are registered by class name and instantiated reflectively (Item 53). In the case of JDBC, Connection plays the part of the service interface, DriverManager.registerDriver is the provider registration API, DriverManager.getConnection is the service access API, and Driver is the service provider interface. There are numerous variants of the service provider framework pattern. For example, the service access API can return a richer service interface than the one required of the provider, using the Adapter pattern [Gamma95, p. 139]. Here is a simple implementation with a service provider interface and a default provider:

// 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();
    }
}

其他回答

API和SPI之间的区别在于API还提供了一些具体的实现。在这种情况下,服务提供者必须实现一些api(称为SPI)

一个例子是JNDI:

JNDI为上下文查找提供了接口和一些类。在IntialContext中提供了默认的查找上下文的方法。该类将在内部使用SPI接口(使用NamingManager)实现特定于提供者的实现。

为了更好地理解,请参阅下面的JNDI体系结构。

在Java世界中,不同的技术都是模块化的,并且可以“插入”到应用服务器中。这两者之间是有区别的

应用服务器 (SPI) 可插拔技术 (API) 最终用户应用程序

这类技术的两个例子是JTA(事务管理器)和JCA (JMS或数据库适配器)。但还有其他原因。

这种可插技术的实现者必须在应用程序服务器中实现可插的SPI,并提供供最终用户应用程序使用的API。来自JCA的一个例子是ManagedConnection接口,它是SPI的一部分,而Connection是最终用户API的一部分。

API代表应用程序编程接口,其中API是访问某种软件或平台提供的服务/功能的手段。

SPI代表服务提供者接口(Service Provider Interface), SPI是为软件或平台注入、扩展或改变行为的方法。

API通常是客户端访问服务的目标,它具有以下属性:

>API是一种访问服务以实现特定行为或输出的编程方式

从API发展的角度来看,添加对客户端来说根本不是问题

但是API一旦被客户端使用,它就不能(也不应该)被修改/删除 除非有适当的沟通,否则就彻底退化了 客户的期望

另一部分的SPI是针对提供者的,具有以下属性:

——>SPI是一种扩展/改变软件或平台行为的方法(可编程vs。 编程)

->SPI的进化不同于API的进化,SPI的移除不是一个问题

添加SPI接口会导致问题,可能会破坏现有的实现

更多解释请点击这里:服务提供者接口

摘自Effective Java,第二版:

A service provider framework is a system in which multiple service providers implement a service, and the system makes the implementations available to its clients, decoupling them from the implementations. There are three essential components of a service provider framework: a service interface, which providers implement; a provider registration API, which the system uses to register implementations, giving clients access to them; and a service access API, which clients use to obtain an instance of the service. The service access API typically allows but does not require the client to specify some criteria for choosing a provider. In the absence of such a specification, the API returns an instance of a default implementation. The service access API is the “flexible static factory” that forms the basis of the service provider framework. An optional fourth component of a service provider framework is a service provider interface, which providers implement to create instances of their service implementation. In the absence of a service provider interface, implementations are registered by class name and instantiated reflectively (Item 53). In the case of JDBC, Connection plays the part of the service interface, DriverManager.registerDriver is the provider registration API, DriverManager.getConnection is the service access API, and Driver is the service provider interface. There are numerous variants of the service provider framework pattern. For example, the service access API can return a richer service interface than the one required of the provider, using the Adapter pattern [Gamma95, p. 139]. Here is a simple implementation with a service provider interface and a default provider:

// 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();
    }
}

我认为SPI通过实现API的某些特性,然后通过服务查找机制将自身注册为可用,从而嵌入到更大的系统中。API由最终用户应用程序代码直接使用,但可以集成SPI组件。这就是封装和直接使用之间的区别。