如何在类路径中查找运行时实现了已定义接口的类?
ServiceLoader 适用于此需求(我认为,尽管我没有使用过),但我需要在 Java 1.5 中进行。
如何在类路径中查找运行时实现了已定义接口的类?
ServiceLoader 适用于此需求(我认为,尽管我没有使用过),但我需要在 Java 1.5 中进行。
Java 1.5没有内置此功能,我自己实现了它,不太复杂。但是,当我们升级到Java 6时,我将不得不用ServiceLoader
替换对我的实现的调用。我本可以在应用程序和加载器之间定义一个小桥梁,但我只在少数地方使用它,而且包装器本身是ServiceLoader的一个很好的候选对象。
这就是核心思想:
public <S> Iterable<S> load(Class<S> ifc) throws Exception {
ClassLoader ldr = Thread.currentThread().getContextClassLoader();
Enumeration<URL> e = ldr.getResources("META-INF/services/" + ifc.getName());
Collection<S> services = new ArrayList<S>();
while (e.hasMoreElements()) {
URL url = e.nextElement();
InputStream is = url.openStream();
try {
BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while (true) {
String line = r.readLine();
if (line == null)
break;
int comment = line.indexOf('#');
if (comment >= 0)
line = line.substring(0, comment);
String name = line.trim();
if (name.length() == 0)
continue;
Class<?> clz = Class.forName(name, true, ldr);
Class<? extends S> impl = clz.asSubclass(ifc);
Constructor<? extends S> ctor = impl.getConstructor();
S svc = ctor.newInstance();
services.add(svc);
}
}
finally {
is.close();
}
}
return services;
}
更好的异常处理留给读者自己去练习。此外,该方法可以参数化,以接受调用者选择的ClassLoader。
javax.imageio.spi.ServiceRegistry
是之前 Java 版本的等价物。它从 Java 1.4 开始可用。
它看起来不像是一个通用的实用类,但它确实是。它甚至比 ServiceLoader
更强大,因为它允许对返回的提供者顺序进行一些控制,并直接访问注册表。
请参见http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html
不幸的是,
Java 1.5 中没有为此构建任何内容...
这只是部分真相。
实际上,存在非标准的 sun.misc.Service
。
http://www.docjar.com/docs/api/sun/misc/Service.html
小心,它不是J2SE API的一部分!
这是Sun JDK的非标准部分。
所以如果你使用JRockit
,你不能依赖它。
ServiceLoader非常基础,并且在JDK中从1.3版开始(非正式地)使用。 ServiceLoader最终成为了一等公民。它只是查找名为您的接口的资源文件,该文件基本上捆绑在库jar的META-INF目录中。
该文件包含要加载的类的名称。
因此,您将拥有一个名为:
META-INF/services/com.example.your.interface
在其中有一行代码:com.you.your.interfaceImpl。
与ServiceLoader相比,我更喜欢Netbeans Lookup。它可以与1.5(或1.4)一起使用。
开箱即用,它所做的与ServiceLoader完全相同,并且非常容易使用。但是它提供了更多的灵活性。
这里是一个链接:http://openide.netbeans.org/lookup/
这篇文章介绍了ServiceLoader,但是在底部提到了Netbeans Lookup: http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html
没有可靠的方法来知道类路径中有哪些类。根据其文档,ServiceLoader依赖于外部文件来告诉它要加载哪些类;您可能希望采取相同的做法。基本思路是创建一个名为要加载类的文件,然后使用反射来实例化它/它们。