如何在Java中实现API/SPI模式? [英] How to implement the API/SPI Pattern in Java?

查看:153
本文介绍了如何在Java中实现API/SPI模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个框架,该框架公开了供开发人员使用的API:

I am creating a framework that exposes an API for developers to use:

public interface MyAPI {
    public void doSomeStuff();

    public int getWidgets(boolean hasRun);
}

所有开发人员应该做的就是根据这些API方法对他们的项目进行编码.我还希望它们能够在运行时类路径上放置不同的驱动程序"/"API绑定"(与JDBC或SLF4J的工作方式相同),并使API方法调用(doSomeStuff()等)在不同的第三方上运行资源(文件,服务器等).因此,相同的代码和API调用将映射到不同资源上的操作,具体取决于运行时类路径所看到的驱动程序/绑定(即myapi-ftpmyapi-sshmyapi-teleportation).

All the developers should have to do is code their projects against these API methods. I also want them to be able to place different "drivers"/"API bindings" on the runtime classpath (the same way JDBC or SLF4J work) and have the API method calls (doSomeStuff(), etc.) operate on different 3rd party resources (files, servers, whatever). Thus the same code and API calls will map to operations on different resources depending on what driver/binding the runtime classpath sees (i.e. myapi-ftp, myapi-ssh, myapi-teleportation).

如何编写(和打包)允许进行此类运行时绑定的SPI,然后将MyAPI调用映射到正确的(具体的)实现?换句话说,如果myapi-ftp允许您从FTP服务器进行getWidgets(boolean),我将如何处理(同时使用API​​和SPI)?

How do I write (and package) an SPI that allows for such runtime binding, and then maps MyAPI calls to the correct (concrete) implementation? In other words, if myapi-ftp allows you to getWidgets(boolean) from an FTP server, how would I could this up (to make use of both the API and SPI)?

具体的有效Java代码示例的加分点!预先感谢!

Bonus points for concrete, working Java code example! Thanks in advance!

推荐答案

看看java.util.ServiceLoader类.

Take a look at the java.util.ServiceLoader class.

通常,想法是这样的:

API罐

  • 提供界面
  • 使用ServiceLoader类查找实现

  • Supply the interface
  • Use the ServiceLoader class to lookup the implementation

    绑定/驱动程序罐

  • 实现界面
  • 创建文件META-INF/并指定实现它的类名

  • Implement the interface
  • Create the file META-INF/ and specify the classname that implements it

    javadocs中有一个很好的例子:

    There's a good example right in the javadocs:

    http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html

    package com.foo;
    
    public interface FooInterface { ... }
    
    public class FooInterfaceFactory {
      public static FooInterface newFooInstance() {
        ServiceLoader<FooInterface> loader = ServiceLoader.load(FooInterface.class);
        Iterator<FooInterface> it = loader.iterator();
        // pick one of the provided implementations and return it.
      }
    

    装订罐

    package com.myfoo;
    public class MyFooImpl implements FooInterface { ... }
    
    META-INF/com.foo.FooInterface
        com.myfoo.MyFooImpl
    

    编辑

    public interface FooSpi { 
       void accepts(String url);
       FooInterface getFooInstance();
    }
    
    
    public class FooInterfaceFactory {
      public static FooInterface getFooInterfaceInstance(String url) {
        ServiceLoader<FooSpi> loader = ServiceLoader.load(FooSpi.class);
        Iterator<FooSpi> it = loader.iterator();
        while (it.hasNext()) {
           FooSpi fooSpi = it.next();
           if (fooSpi .accepts(url)) {
             return fooSpi.getFooInstance();
           }
        }
    
        return null;
      }
    }
    

    当然,将文件名更改为com.foo.FooSpi并提供FooSpi的实现.这样您就可以将公共API与Spi接口隔离开来.

    And of course, change the filename to com.foo.FooSpi and provide an implementation of FooSpi. That will allow you to segregate the public API from the Spi interface.

    如果要隐藏accepts方法,则始终可以有第二个接口,它是您的公共API,并且t

    If you want to hide the accepts method, you could always have a second interface which is your public API, and t

    这篇关于如何在Java中实现API/SPI模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆