一尘不染

如何在Java中实现API / SPI模式?

java

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

public interface MyAPI {
    public void doSomeStuff();

    public int getWidgets(boolean hasRun);
}

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

我怎样写(和封装)的SPI允许这样的运行时绑定, 再映射MyAPI调用正确的(混凝土)执行?换句话说,如果myapi- ftp允许您getWidgets(boolean)从FTP服务器访问,该如何处理(以同时使用API​​和SPI)?

具体的,有效的Java代码示例的加分项!提前致谢!


阅读 284

收藏
2020-12-03

共1个答案

一尘不染

看一看java.util.ServiceLoader类。

通常,这个想法是这样的:

API罐

  • 提供接口
  • 使用ServiceLoader类查找实现

绑定/驱动程序罐

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

javadocs中有一个很好的例子:

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

API罐

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

编辑

SPI示例

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接口隔离开来。

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

2020-12-03