首页 文章

SPI和API之间的区别?

提问于
浏览
269

Service Provider Interface (SPI)Application Programming Interface (API)之间有什么区别?

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

9 回答

  • 16
    • API是您调用并用于实现目标的类/接口/方法/ ...的描述,以及

    • SPI是您扩展和实现以实现目标的类/接口/方法/ ...的描述 .

    换句话说,API告诉您特定的类/方法为您做了什么,SPI告诉您必须做什么来符合 .

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

    然而,有时它们重叠 . The Connection interfaceboth SPI和API:当您使用JDBC驱动程序时,它会定期使用它,并且需要由JDBC驱动程序的开发人员实现 .

  • 11

    来自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();
        }
    }
    
  • 2

    当API另外提供一些具体实现时,API和SPI之间的区别就出现了 . 在这种情况下,服务提供商必须实现一些API(称为SPI)

    一个例子是JNDI:

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

    有关更好的理解,请参阅下面的JNDI体系结构 .

    Enter image description here

  • 2

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

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

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

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

    • 从API发展的角度来看,添加对客户来说完全没问题

    • 但是API曾经被客户使用过,除非有适当的通信,否则它不能(也不应该)被更改/删除,因为它完全降低了客户的期望

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

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

    • SPI演化不同于API演进,在SPI中移除不是问题

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

    有关更多说明,请单击此处:Service Provider Interface

  • 342

    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端)不需要关心是否存在版本控制系统,或者它是什么 .

  • 49

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

  • 18

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

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

  • 4

    在Java世界中,不同的技术意味着模块化并可“插入”应用程序服务器 . 然后有一个区别

    • 应用程序服务器

    • [SPI]

    • 可插拔技术

    • [API]

    • 最终用户应用程序

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

    然后,这种可插拔技术的实现者必须将SPI实现为可插入应用程序 . 服务器并提供最终用户应用程序使用的API . JCA的一个例子是ManagedConnection接口,它是SPI的一部分,Connection是最终用户API的一部分 .

  • 4

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

    API/SPI split is only required when platform is expected to evolve. 如果您编写API和"know"它将不需要任何未来的改进,没有真正的理由将代码分成两部分(除了进行干净的对象设计) .

    但这种情况几乎从未出现过这种情况,人们需要自由地将API与未来的需求一起发展 - 以向后兼容的方式 .

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

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


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

    Collections.emptySet();
    

    由于所有客户端都是"calling"但不是"implementing",因此JDK的作者在JDK未来版本的 Collections 对象中是 free to add new methods . 他们可以肯定它不会破坏任何客户,即使可能有数百万的用法 .


    SPI: Collection 是一个界面,暗示任何人都可以实现自己的版本 . 因此,JDK can't add new methods into it 的作者会破坏所有编写自己的 Collection 实现(*)的客户端 .

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


    你可能已经看到了这一点 . 如果您将两个部分组合到一个类中,则会阻止您的API添加任何内容 . 那个's also the reason why good Java APIs and Frameworks don'暴露 abstract class ,因为他们会阻止他们在向后兼容方面的未来发展 .

    如果仍然不清楚,我建议检查this page,这将更详细地解释上述内容 .


    (*)请注意,这只适用于Java 1.8,它引入了接口中定义的 default 方法的概念 .

相关问题