服务提供商接口(SPI)和应用程序编程接口(API)有什么区别?
更具体地说,对于Java库,是什么使它们成为API和/或SPI?
服务提供商接口(SPI)和应用程序编程接口(API)有什么区别?
更具体地说,对于Java库,是什么使它们成为API和/或SPI?
Answers:
换句话说,API会告诉您特定的类/方法为您执行什么操作,而SPI则告诉您必须执行哪些操作才能符合要求。
通常,API和SPI是分开的。例如,在JDBC中,Driver
该类是SPI的一部分:如果只想使用JDBC,则不需要直接使用它,但是实现JDBC驱动程序的每个人都必须实现该类。
但是,有时它们会重叠。该Connection
接口是两个 SPI和API:当您使用JDBC驱动程序,它需要通过JDBC驱动程序的开发者来实现您可以使用它定期。
@SomeAnnotation
我的类以使其被某个框架使用,那么SomeAnnotation.class
即使我没有在技术上扩展或实现它,该注释类也将被视为SPI的一部分吗?
从有效的Java,第二版:
服务提供者框架是一个系统,其中多个服务提供者实现了一项服务,并且系统使实现可供其客户端使用,从而将它们与实现分离。
服务提供者框架包含三个基本组件:服务提供者实现的服务接口;提供者注册API,系统用来注册实现,使客户可以访问它们;和服务访问API,客户端使用该API来获取服务实例。服务访问API通常允许但不要求客户端指定一些用于选择提供程序的条件。在没有这种规范的情况下,API返回默认实现的实例。服务访问API是“灵活的静态工厂”,它构成了服务提供者框架的基础。
服务提供者框架的可选第四组件是服务提供者接口,提供者实施该接口以创建其服务实现的实例。在没有服务提供者接口的情况下,通过类名称注册实现,并以反射方式实例化(项目53)。对于JDBC,Connection充当服务接口的一部分,DriverManager.registerDriver是提供程序注册API,DriverManager.getConnection是服务访问API,Driver是服务提供程序接口。
服务提供者框架模式有多种变体。例如,使用适配器模式[Gamma95,p。1],服务访问API可以返回比提供者所需的服务接口更丰富的服务接口。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();
}
}
API代表应用程序编程接口,其中API是访问某种软件或平台提供的服务/功能的一种方式。
SPI代表服务提供商接口,其中SPI是注入,扩展或更改软件或平台行为的方式。
API通常是客户端访问服务的目标,并且具有以下属性:
-> API是一种访问服务以实现特定行为或输出的编程方式
->从API演变的角度来看,添加对于客户端来说完全没有问题
->但是API一旦被客户端使用,除非有适当的通信,否则它不能(也不应)被更改/删除,因为它完全降低了客户端的期望
另一方面,SPI面向提供者,并具有以下属性:
-> SPI是一种扩展/更改软件或平台行为的方式(可编程与可编程)
-> SPI的演进与API的演进不同,在SPI移除方面不是问题
->添加SPI接口将导致问题并可能破坏现有的实现
有关更多说明,请单击此处:服务提供商接口
NetBeans的常见问题解答:什么是SPI?与API有何不同?
API是一个通用术语-应用程序编程接口的缩写-它表示某个软件公开的某些东西(在Java中,通常是某些Java类),它允许其他软件与其通信。
SPI代表服务提供商接口。它是所有事物的子集,可以是特定于API的特定情况,在这种情况下,库提供了由应用程序(或API库)调用的类,并且通常会更改应用程序能够执行的操作。
经典示例是JavaMail。它的API有两个方面:
- API端-如果您正在编写邮件客户端或想阅读邮箱,则可以调用
- SPI端(如果要提供一个有线协议处理程序,以允许JavaMail与新型服务器通信,例如新闻或IMAP服务器)
API的用户很少需要查看或交谈SPI类,反之亦然。
在NetBeans中,当您看到术语SPI时,通常是在谈论模块可以在运行时注入的类,这些类允许NetBeans做新的事情。例如,存在用于实现版本控制系统的通用SPI。不同的模块为CVS,Subversion,Mercurial和其他版本控制系统提供了该SPI的实现。但是,处理文件(API端)的代码无需关心是否存在版本控制系统或它是什么。
有一个方面似乎并没有特别强调,但是对于理解API / SPI分离背后的原因非常重要。
仅在预期平台发展时才需要API / SPI拆分。如果您编写了一个API并“知道”它以后将不再需要任何改进,则没有真正的理由将您的代码分为两部分(除了进行干净的对象设计之外)。
但这几乎绝不是这种情况,人们需要自由地以向后兼容的方式与未来的需求一起发展API。
请注意,以上所有条件均假定您正在构建供其他人使用和/或扩展的平台,而不是您自己的API,在此平台上您可以控制所有客户端代码,因此可以根据需要进行重构。
让我们在一个众所周知的Java对象Collection
和上显示它Collections
。
API: Collections
是一组实用程序的静态方法。通常定义代表API对象的类是final
因为它可以确保(在编译时)没有客户端可以“实现”该对象,并且它们可以依赖于“调用”其静态方法,例如
Collections.emptySet();
由于所有客户端都是“调用”而不是“实现”,因此JDK的作者可以在JDK 的未来版本中自由地向Collections
对象添加新方法。他们可以确保它不会破坏任何客户端,即使可能有数百万种用法。
SPI: Collection
是一个接口,它意味着任何人都可以实现自己的版本。因此,JDK的作者不能在其中添加新方法,因为它将破坏所有编写自己的Collection
实现(*)的客户。
通常,当需要添加其他方法时,Collection2
需要创建新接口,例如,扩展前一个接口。然后,SPI客户端可以决定是迁移到新版SPI并实施其另一种方法,还是坚持使用旧版方法。
您可能已经明白了这一点。如果将这两部分组合到一个类中,则将阻止您的API进行任何添加。这也是优秀的Java API和框架之所以不公开的原因,abstract class
因为它们会阻止它们在向后兼容性方面的未来发展。
如果仍然不清楚,建议您查看此页面,其中更详细地说明了上述内容。
(*)请注意,只有在Java 1.8引入default
了接口中定义的方法的概念之前,这才是正确的。
在Java世界中,不同的技术意味着可以模块化并且可以“插入”到应用程序服务器中。然后有一个区别
此类技术的两个示例是JTA(事务管理器)和JCA(用于JMS或数据库的适配器)。但是还有其他。
然后,这种可插拔技术的实现者必须实现SPI,以便在应用程序中可插拔。服务器并提供供最终用户应用程序使用的API。JCA的一个示例是ManagedConnection接口,它是SPI的一部分,而Connection是最终用户API的一部分。