Service Provider Interface (SPI)和Application Programming Interface (API)之间的区别是什么?
更具体地说,对于Java库,是什么使它们成为API和/或SPI?
答案 0 :(得分:358)
换句话说,API告诉您特定的类/方法为您做了什么,SPI告诉您必须采取哪些措施来符合。
通常API和SPI是分开的。例如,在JDBC the Driver
class中是SPI的一部分:如果您只是想使用JDBC,则不需要直接使用它,但实现JDBC驱动程序的每个人都必须实现该类。
然而,有时它们重叠。 The Connection
interface SPI和API:您在使用JDBC驱动程序时会定期使用它,并且需要由JDBC驱动程序的开发人员实现。
答案 1 :(得分:53)
来自 Effective Java,2nd Edition :
服务提供商框架是一个 系统中有多种服务 提供者实现服务,和 系统实现 可供客户使用,解耦 他们来自实施。
有三个基本要素 服务提供者框架:a 服务接口,哪些提供商 实行;提供者注册 API,系统用于注册 实现,为客户提供访问权限 给他们;和服务访问API, 哪些客户用来获取 服务的实例。服务 访问API通常允许但确实允许 不要求客户指定一些 选择提供者的标准。在 没有这样的规范, API返回一个实例 默认实现。服务 访问API是“灵活的静态 工厂“,形成了基础 服务提供者框架。
a的可选第四个组成部分 服务提供者框架是一个 服务提供者接口,其中 提供者实现创建 他们的服务实例 实现。没有了 服务提供商界面, 实现是通过注册的 类名和实例化 反思地(项目53)。如果是 JDBC,Connection是其中的一部分 服务界面, DriverManager.registerDriver是 提供者注册API, DriverManager.getConnection是 服务访问API,而驱动程序是 服务提供商界面。
有许多变种 服务提供者框架模式。 例如,服务访问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();
}
}
答案 2 :(得分:19)
API 代表应用程序编程接口,其中API是访问由某种软件或平台提供的服务/功能的工具。
SPI 代表服务提供商接口,其中SPI是注入,扩展或改变软件或平台行为的方式。
API通常是客户端访问服务的目标,它具有以下属性:
- &gt; API是一种访问服务以实现特定行为或输出的编程方式
- &gt;从API发展的角度来看,添加对客户来说完全没问题
- &gt;但是API曾经被客户使用过,它不能(也不应该)被更改/删除 除非有适当的通信,因为它完全退化了 客户期望
另一部分的SPI针对提供商,具有以下属性:
- &gt; SPI是一种扩展/改变软件或平台行为的方法(可编程vs. 编程)
- &gt; SPI演变与API演变不同,SPI移除不是问题
- &gt;添加SPI接口会导致问题并可能破坏现有的实现
有关详细说明,请点击此处:Service Provider Interface
答案 3 :(得分:18)
当API另外提供一些具体实现时,API和SPI之间的区别就出现了。在这种情况下,服务提供商必须实现一些API(称为SPI)
一个例子是JNDI:
JNDI提供接口&amp;一些用于上下文查找的类。 IntialContext中提供了查找上下文的默认方法。该类内部将使用SPI接口(使用NamingManager)进行提供程序特定的实现。
请参阅下面的JNDI架构以便更好地理解。
答案 4 :(得分:11)
NetBeans的常见问题解答:What is an SPI? How is it different from an API?
API是一个通用术语 - 应用程序编程接口的首字母缩写 - 它表示某种软件公开的东西(在Java中,通常是一些Java类),允许其他软件与之通信。
SPI代表服务提供商接口。它是所有事物的子集,可以是特定于API的情况,其中库提供由应用程序(或API库)调用的类,并且通常会更改应用程序能够执行的操作。
经典的例子是JavaMail。它的API有两个方面:
- API端 - 如果您正在编写邮件客户端或想要阅读邮箱,则会调用
- SPI方面,如果您提供有线协议处理程序以允许JavaMail与新类型的服务器(例如新闻或IMAP服务器)通信
API的用户很少需要查看或与SPI类通信,反之亦然。
在NetBeans中,当您看到术语SPI时,通常会讨论模块可以在运行时注入的类,这些类允许NetBeans执行新操作。例如,有一个用于实现版本控制系统的通用SPI。不同的模块为CVS,Subversion,Mercurial和其他版本控制系统提供了SPI的实现。但是,处理文件的代码(API端)不需要关心是否存在版本控制系统或它是什么。
答案 5 :(得分:4)
我认为通过实现API的某些功能,将SPI插入更大的系统,然后通过服务查找机制将其注册为可用。最终用户应用程序代码直接使用API,但可以集成SPI组件。这是封装和直接使用之间的区别。
答案 6 :(得分:4)
服务提供者接口是所有提供者必须实现的服务接口。如果现有的提供程序实现都不适合您,则需要编写自己的服务提供程序(实现服务接口)并在某处注册(请参阅Roman的有用帖子)。
如果您正在重用服务接口的现有提供程序实现,那么您基本上使用的是该特定提供程序的API,其中包括服务接口的所有方法以及它自己的一些公共方法。如果您在SPI之外使用提供程序API的方法,则使用提供程序特定的功能。
答案 7 :(得分:3)
有一个方面似乎没有多少突出显示,但对于理解API / SPI分裂存在背后的推理非常重要。
只有在预期平台发展时才需要API / SPI拆分。如果您编写API并且&#34;知道&#34; 它赢得了&#39; t需要任何未来的改进,没有真正的理由将你的代码分成两部分(除了制作干净的对象设计)。
但这种情况几乎从未发生过,人们需要有一种自由来与未来的需求一起发展API - 以向后兼容的方式。
请注意,以上所有内容都假定您正在构建其他人使用和/或扩展的平台,而不是您自己的API,您可以控制所有客户端代码,因此可以根据需要进行重构。 / em>的
让我们在一个众所周知的Java对象Collection
和Collections
上展示它。
API: Collections
是一组实用程序静态方法。表示API对象的类通常被定义为final
,因为它确保(在编译时)没有客户端能够&#34;实现&#34; 该对象并且它们可以依赖于&#34;调用&#34; 其静态方法,例如
Collections.emptySet();
由于所有客户&#34;正在调用&#34; 而不是&#34;实施&#34; ,因此JDK的作者可以免费添加新方法到JDK未来版本的Collections
对象中。他们可以肯定它不会破坏任何客户,即使可能有数百万的用法。
SPI: Collection
是一个界面,暗示任何人都可以实现自己的版本。因此,JDK 的作者无法在其中添加新方法,因为它会破坏编写自己的Collection
实现(*)的所有客户端。
通常,当需要添加其他方法时,新界面,例如,需要创建扩展前者的Collection2
。 SPI客户端然后可以决定是否迁移到新版本的SPI并实施它的附加方法或者是否坚持使用旧版本。
你可能已经看到了这一点。如果将两个部分组合成一个类,则会阻止您的API添加任何内容。这也是优秀的Java API和框架不会暴露abstract class
的原因,因为它们会阻止他们在向后兼容方面的未来发展。
如果某些内容仍然不明确,建议您查看this page,其中详细说明了上述内容。
(*)请注意,这只适用于Java 1.8,它引入了接口中定义的default
方法的概念。
答案 8 :(得分:2)
在Java世界中,不同的技术意味着模块化并可“插入”应用程序服务器。
之间存在差异此类技术的两个示例是JTA(事务管理器)和JCA(适用于JMS或数据库的适配器)。但还有其他人。
这种可插拔技术的实现者必须在应用程序中实现SPI可插拔。服务器并提供最终用户应用程序使用的API。 JCA的一个示例是ManagedConnection接口,它是SPI的一部分,Connection是最终用户API的一部分。