Java SPI和API的区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2954372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 14:53:49  来源:igfitidea点击:

Difference between SPI and API?

javaapi

提问by kctang

What is the difference between Service Provider Interface (SPI)and Application Programming Interface (API)?

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

More specifically, for Java libraries, what makes them an API and/or SPI?

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

采纳答案by Joachim Sauer

  • The API is the description of classes/interfaces/methods/... that you call and useto achieve a goal, and
  • the SPI is the description of classes/interfaces/methods/... that you extend and implementto achieve a goal.
  • API 是对类/接口/方法/...的描述,您调用并使用它们来实现目标,以及
  • SPI 是对类/接口/方法/...的描述,您可以扩展和实现这些来实现目标。

Put differently, the API tells you what a specific class/method does for you, and the SPI tells you what you must do to conform.

换句话说,API 告诉您特定的类/方法为您做什么,而 SPI 告诉您必须做什么才能符合要求。

Usually API and SPI are separate. For example, in JDBC the Driverclassis part of the SPI: If you simply want to use JDBC, you don't need to use it directly, but everyone who implements a JDBC driver must implement that class.

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

Sometimes they overlap, however. The Connectioninterfaceis bothSPI and API: You use it routinely when you use a JDBC driver and it needs to be implemented by the developer of the JDBC driver.

然而,有时它们会重叠。Connection接口两个SPI和API:当您使用JDBC驱动程序,它需要通过JDBC驱动程序的开发者来实现您可以使用它定期。

回答by Chris Dennett

I suppose an SPI slots into a larger system by implementing certain features of an API, and then registering itself as being available via service lookup mechanisms. An API is used by the end-user application code directly, but may integrate SPI components. It's the difference between encapsulation and direct usage.

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

回答by ewernli

In the Java world, different technologies are meant to be modular and "pluggable" into an application server. There is then a difference between

在 Java 世界中,不同的技术旨在模块化和“可插入”到应用程序服务器中。然后有区别

  • the application server
    • [SPI]
  • the pluggable technology
    • [API]
  • the end user application
  • 应用服务器
    • [SPI]
  • 可插拔技术
    • [API]
  • 最终用户应用程序

Two examples of such technologies are JTA (the transaction manager) and JCA (adapter for JMS or database). But there are others.

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

Implementer of such a pluggable technology must then implement the SPI to be pluggable in the app. server and provide an API to be used by the end-user application. An example from JCA is the ManagedConnectioninterface which is part of the SPI, and the Connectionthat is part of the end-user API.

然后,这种可插拔技术的实现者必须在应用程序中实现可插拔的 SPI。服务器并提供供最终用户应用程序使用的 API。JCA 的一个示例是作为 SPI 一部分的ManagedConnection接口,以及作为最终用户 API 一部分的Connection

回答by Roman

From Effective Java, 2nd Edition:

来自Effective Java,第 2 版

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:

服务提供者框架是一个系统,其中多个服务提供者实现一个服务,该系统使实现对其客户可用,将它们与实现分离。

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

服务提供者框架的第四个可选组件是服务提供者接口,提供者实现该接口以创建其服务实现的实例。在没有服务提供者接口的情况下,实现通过类名注册并反射性地实例化(条目 53)。在JDBC的情况下,Connection是服务接口的部分,DriverManager.registerDriver是提供者注册API,DriverManager.getConnection是服务访问API,Driver是服务提供者接口。

服务提供者框架模式有许多变体。例如,服务访问 API 可以返回一个比提供者所需的服务接口更丰富的服务接口,使用适配器模式 [Gamma95, p. 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();
    }
}

回答by Ondra ?i?ka

NetBeans' FAQ: What is an SPI? How is it different from an API?

NetBeans 的常见问题解答:什么是 SPI?它与 API 有何不同?

API is a general term - an acronym for Application Programming Interface - it means something (in Java, usually some Java classes) a piece of software exposes, which allows other software to communicate with it.

SPI stands for Service Provider Interface. It is a subset of all things that can be API specific to situations where a library is providing classes which are called by the application (or API library), and which typically change the things the application is able to do.

The classic example is JavaMail. Its API has two sides:

  • The API side — which you call if you are writing a mail client or want to read a mailbox
  • The SPI side if you are providing a wire-protocol handler to allow JavaMail to talk to a new kind of server, such as a news or IMAP server

Users of the API rarely need to see or talk to the SPI classes, and vice-versa.

In NetBeans, when you see the term SPI, it is usually talking about classes that a module can inject at runtime which allow NetBeans to do new things. For example, there is a general SPI for implementing version control systems. Different modules provide implementations of that SPI for CVS, Subversion, Mercurial and other revision control systems. However, the code that deals with files (the API side) does not need to care if there is a version control system, or what it is.

API 是一个通用术语——应用程序编程接口的首字母缩写词——它的意思是(在 Java 中,通常是一些 Java 类)一个软件公开的东西,它允许其他软件与其进行通信。

SPI 代表服务提供者接口。它是所有可以是 API 特定的事物的子集,在库提供由应用程序(或 API 库)调用的类的情况下,这些类通常会更改应用程序能够执行的操作。

典型的例子是 JavaMail。它的 API 有两个方面:

  • API 端 - 如果您正在编写邮件客户端或想要读取邮箱,您可以调用它
  • SPI 端,如果您提供一个有线协议处理程序来允许 JavaMail 与一种新类型的服务器通信,例如新闻或 IMAP 服务器

API 的用户很少需要查看或与 SPI 类对话,反之亦然。

在 NetBeans 中,当您看到术语 SPI 时,它通常指的是模块可以在运行时注入的类,这些类允许 NetBeans 执行新操作。例如,有一个用于实现版本控制系统的通用 SPI。不同的模块为 CVS、Subversion、Mercurial 和其他版本控制系统提供该 SPI 的实现。然而,处理文件的代码(API 端)不需要关心是否有版本控制系统,或者它是什么。

回答by tapasvi

Service provider interface is the service interface which all providers must implement. If none of the existing provider implementations work for you, you need to write your own service provider (implementing the service interface) and register somewhere (see the useful post by Roman).

服务提供者接口是所有提供者必须实现的服务接口。如果现有的提供者实现都不适合您,您需要编写自己的服务提供者(实现服务接口)并在某处注册(请参阅 Roman 的有用帖子)。

If you're reusing the existing provider implementation of the service interface, you're basically using the API of that particular provider, which include all the methods of service interface plus a few public methods of its own. If you're using methods of provider API outside the SPI, you're using provider specific features.

如果您正在重用服务接口的现有提供者实现,那么您基本上是在使用该特定提供者的 API,其中包括服务接口的所有方法以及它自己的一些公共方法。如果您在 SPI 之外使用提供程序 API 的方法,那么您正在使用提供程序特定的功能。

回答by Sandeep Jindal

The difference between API and SPI comes when an API additionally provides some concrete implementations. In that case, the service provider has to implement a few APIs (called SPI)

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

An example is JNDI:

一个例子是 JNDI:

JNDI provides interfaces & some classes for context lookup. The default way to lookup a context is provided in IntialContext. This class internally will use SPI interfaces (using NamingManager) for provider specific implementations.

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

See the JNDI Architecture below for better understanding.

请参阅下面的 JNDI 架构以获得更好的理解。

Enter image description here

在此处输入图片说明

回答by Venkata Aditya Pavan

APIstands for Application Programming Interface, where API is a means for accessing a service / function provided by some kind of software or a platform.

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

SPIstands for Service Provider Interface, where SPI is way to inject, extend or alter the behavior for software or a platform.

SPI代表服务提供者接口,其中 SPI 是注入、扩展或改变软件或平台行为的方式。

API is normally target for clients to access a service and it has the following properties:

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

-->API is a programmatic way of accessing a service to achieve a certain behavior or output

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

-->From API evolution point of view, addition is no problem at all for clients

-->从API演进的角度来看,加法对客户端完全没有问题

-->But API's once utilized by clients it can not (and should not) be altered / deleted unless there are an appropriate communications, since its a complete degradation of the client expectation

-->但是API一旦被客户使用就不能(也不应该)被更改/删除,除非有适当的通信,因为它完全降低了客户的期望

SPI on the other part are targeted for providers and has the following properties:

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

-->SPI is a way to extend / alter the behavior of a software or a platform (programmable vs. programmatic)

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

-->SPI evolution is different from API evolution, in SPI removal is not an issue

-->SPI 演进与 API 演进不同,在 SPI 删除中不是问题

-->Addition of SPI interfaces will cause problems and may break existing implementations

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

For more explanation click here : Service Provider Interface

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

回答by Martin Janí?ek

There is one aspect which doesn't seem to be highlighted much but is very important to understand the reasoning behind the existence of API/SPI split.

有一个方面似乎没有特别突出,但对于理解 API/SPI 拆分存在背后的原因非常重要。

API/SPI split is only required when platform is expected to evolve.If you write an API and "know"it won't require any future improvements ever, there is no real reasons for splitting your code into the two parts (besides making clean object design).

API/SPI 拆分仅在预期平台发展时才需要。如果您编写一个 API 并且“知道”它不需要任何未来的改进,那么将您的代码分成两部分(除了进行干净的对象设计)没有真正的理由。

But this is almost never the case and people need to have a freedom to evolve API together with future requirements - in a backward compatible way.

但这几乎从来都不是这种情况,人们需要自由地根据未来的需求来发展 API - 以向后兼容的方式。

Note that all of the above assumes you're building platform that other people use and/or extend and not your own API where you have all client code under control and thus can refactor however you need.

请注意,以上所有内容都假设您正在构建其他人使用和/或扩展的平台,而不是您自己的 API,您可以控制所有客户端代码,因此可以根据需要进行重构。

Lets show it on one of the well known Java objects Collectionand Collections.

让我们在一个众所周知的 Java 对象CollectionCollections.



API:Collectionsis a set of utility static methods. Often classes representing API object are defined as finalas it ensures (at compilation time) that no client can ever "implement"that object and they can depend on "calling"its static methods, e.g.

API:Collections是一组实用的静态方法。通常,表示 API 对象的类被定义为final因为它确保(在编译时)没有客户端可以“实现”该对象,并且它们可以依赖于“调用”其静态方法,例如

Collections.emptySet();

Since all clients are "calling"but not "implementing", authors of JDK are free to add new methodsinto the Collectionsobject in the future version of JDK. They can be sure it can't break any client, even if there are probably milions of usages.

由于所有客户端都在“调用”而不是“实现”,因此 JDK 的作者可以在 JDK的未来版本中自由地将新方法添加Collections对象中。他们可以确定它不会破坏任何客户端,即使可能有数百万次使用。



SPI:Collectionis an interface which implies that anyone can implement her own version of it. Thus, authors of JDK can't add new methods into itas it would break all clients who wrote their own Collectionimplementation (*).

SPI:Collection是一个接口,意味着任何人都可以实现她自己的版本。因此,JDK 的作者不能向其中添加新方法,因为它会破坏所有编写自己Collection实现的客户端(*)。

Typically when additional method is required to be added, new interface, e.g. Collection2which extends the former one needs to be created. SPI client then can decide whether to migrate to the new version of SPI and implement it's additional method or whether to stick with the older one.

通常,当需要添加其他方法时,Collection2需要创建新接口,例如扩展前一个接口。SPI 客户端然后可以决定是否迁移到新版本的 SPI 并实现它的附加方法,或者是否坚持使用旧版本。



You might already seen the point. If you combine both pieces together into a single class, your API is blocked from any additions. That's also the reason why good Java APIs and Frameworks don't expose abstract classas they would block their future evolution with respect to the backward compatibility.

你可能已经看到了这一点。如果您将两个部分组合成一个类,则您的 API 将无法添加任何内容。这也是为什么优秀的 Java API 和框架不会公开的原因,abstract class因为它们会阻碍它们在向后兼容性方面的未来发展。

If something is still unclear, I recommend to check this pagewhich explains the above in more detail.

如果仍有不清楚的地方,我建议查看此页面,其中更详细地解释了上述内容。



(*) Note this is true only until Java 1.8 which introduces concept of defaultmethods defined in an interface.

(*) 请注意,只有在 Java 1.8 引入了default在接口中定义的方法的概念之前,这才是正确的。