问题描述
我正在创建一个框架,该框架公开了供开发人员使用的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-ftp
,myapi-ssh
,myapi-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罐
绑定/驱动程序罐
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模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!