Joa*_*uer 375
换句话说,API告诉您特定的类/方法为您做了什么,SPI告诉您必须做什么来符合.
通常API和SPI是分开的.例如,在JDBC中,Driver类是SPI的一部分:如果您只是想使用JDBC,则不需要直接使用它,但实现JDBC驱动程序的每个人都必须实现该类.
然而,有时它们重叠.该Connection接口是两个 SPI和API:当您使用JDBC驱动程序,它需要通过JDBC驱动程序的开发者来实现您可以使用它定期.
Rom*_*man 57
来自Effective Java,第2版:
服务提供者框架是多个服务提供者实现服务的系统,并且系统使实现可用于其客户端,从而将它们与实现分离.
服务提供者框架有三个基本组件:服务接口,提供者实现; 提供者注册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();
}
}
Run Code Online (Sandbox Code Playgroud)
San*_*dal 21
当API另外提供一些具体实现时,API和SPI之间的区别就出现了.在这种情况下,服务提供商必须实现一些API(称为SPI)
一个例子是JNDI:
JNDI为上下文查找提供接口和一些类.IntialContext中提供了查找上下文的默认方法.此类内部将使用SPI接口(使用NamingManager)进行提供程序特定的实现.
有关更好的理解,请参阅下面的JNDI体系结构.

小智 21
API代表应用程序编程接口,其中API是用于访问由某种软件或平台提供的服务/功能的手段.
SPI代表服务提供者接口,SPI是注入,扩展或改变软件或平台行为的方式.
API通常是客户端访问服务的目标,它具有以下属性:
- > API是一种以编程方式访问服务以实现某种行为或输出
- >从API发展的角度来看,添加对客户来说完全没问题
- >但是API曾经被客户使用过,除非有适当的通信,否则它不能(也不应该)被更改/删除,因为它完全降低了客户的期望
另一部分的SPI针对提供商,具有以下属性:
- > SPI是一种扩展/改变软件或平台行为的方法(可编程与程序化)
- > SPI演化不同于API演进,在SPI移除中不是问题
- >添加SPI接口会导致问题并可能破坏现有的实现
有关更多说明,请单击此处:服务提供商接口
Ond*_*žka 12
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();
Run Code Online (Sandbox Code Playgroud)
由于所有客户端都在“调用”而不是“实现”,因此 JDK 的作者可以在 JDK的未来版本中自由地将新方法添加到Collections对象中。他们可以确定它不会破坏任何客户端,即使可能有数百万次使用。
SPI: Collection是一个接口,意味着任何人都可以实现她自己的版本。因此,JDK 的作者不能向其中添加新方法,因为它会破坏所有编写自己Collection实现的客户端(*)。
通常,当需要添加其他方法时,Collection2需要创建新接口,例如扩展前一个接口。SPI 客户端然后可以决定是否迁移到新版本的 SPI 并实现它的附加方法,或者是否坚持使用旧版本。
你可能已经看到了这一点。如果您将两个部分组合成一个类,则您的 API 将无法添加任何内容。这也是为什么优秀的 Java API 和框架不会公开的原因,abstract class因为它们会阻碍它们在向后兼容性方面的未来发展。
如果仍有不清楚的地方,我建议查看此页面,其中更详细地解释了上述内容。
(*) 请注意,只有在 Java 1.8 引入了default在接口中定义的方法的概念之前,这才是正确的。
| 归档时间: |
|
| 查看次数: |
88961 次 |
| 最近记录: |