类似于 Java 1.5 中的 ServiceLoader 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/251336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is something similar to ServiceLoader in Java 1.5?
提问by Telcontar
How do I discover classes at runtime in the classpath which implements a defined interface?
如何在运行时在实现定义接口的类路径中发现类?
ServiceLoader suits well (I think, I haven't used it), but I need do it in Java 1.5.
ServiceLoader 很适合(我想,我还没有使用过它),但我需要在 Java 1.5 中使用它。
采纳答案by erickson
There's nothing built into Java 1.5 for this. I implemented it myself; it's not too complicated. However, when we upgrade to Java 6, I will have to replace calls to my implementation with calls to ServiceLoader
. I could have defined a little bridge between the app and the loader, but I only use it in a few places, and the wrapper itself would be a good candidate for a ServiceLoader.
Java 1.5 中没有为此内置任何内容。我自己实现了;这不是太复杂。但是,当我们升级到 Java 6 时,我将不得不用对ServiceLoader
. 我本可以在应用程序和加载器之间定义一个小桥梁,但我只在少数地方使用它,而包装器本身将是 ServiceLoader 的一个很好的候选者。
This is the core idea:
这是核心思想:
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;
}
Better exception handling is left as an exercise for the reader. Also, the method could be parameterized to accept a ClassLoader of the caller's choosing.
更好的异常处理留给读者作为练习。此外,该方法可以被参数化以接受调用者选择的 ClassLoader。
回答by Michael Myers
There is no reliable way to know what classes are in the classpath. According to its documentation, ServiceLoader relies on external files to tell it what classes to load; you might want to do the same. The basic idea is to have a file with the name of the class(es) to load, and then use reflection to instantiate it/them.
没有可靠的方法来了解类路径中的类。根据其文档,ServiceLoader 依赖于外部文件来告诉它要加载哪些类;你可能也想这样做。基本思想是有一个要加载的类名的文件,然后使用反射来实例化它/它们。
回答by Will Hartung
ServiceLoader is quite basic, and has been in use (informally) within the JDK since 1.3. ServiceLoader just finally made it a first class citizen. It simply looks for a resource file named for your interface, which is basically bundled in the META-INF directory of a library jar.
ServiceLoader 非常基础,自 1.3 以来一直在 JDK 中(非正式地)使用。ServiceLoader 终于让它成为一等公民。它只是查找以您的接口命名的资源文件,该文件基本上捆绑在库 jar 的 META-INF 目录中。
That file contains the name of the class to load.
该文件包含要加载的类的名称。
So, you'd have a file named:
所以,你会有一个名为:
META-INF/services/com.example.your.interface
META-INF/services/com.example.your.interface
and inside it is a single line: com.you.your.interfaceImpl.
里面只有一行:com.you.your.interfaceImpl。
In lieu of ServiceLoader, I like Netbeans Lookup. It works with 1.5 (and maybe 1.4).
代替 ServiceLoader,我喜欢 Netbeans Lookup。它适用于 1.5(也可能是 1.4)。
Out of the box, it does the exact same thing as ServiceLoader, and it's trivial to use. But it offers a lot more flexibility.
开箱即用,它与 ServiceLoader 执行完全相同的操作,并且使用起来很简单。但它提供了更多的灵活性。
Here's a link: http://openide.netbeans.org/lookup/
这是一个链接:http: //openide.netbeans.org/lookup/
Here's a article about ServiceLoader, but it mentions Netbeans Lookup at the bottom: http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html
这是一篇关于 ServiceLoader 的文章,但它在底部提到了 Netbeans Lookup:http: //weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html
回答by Marco Hunsicker
javax.imageio.spi.ServiceRegistry
is the equivalent with prior Java versions. It's available since Java 1.4.
javax.imageio.spi.ServiceRegistry
与之前的 Java 版本等效。它从 Java 1.4 开始可用。
It does not look like a general utility class, but it is. It's even a bit more powerful than ServiceLoader
, as it allows some control over the order of the returned providers and direct access to the registry.
它看起来不像一个通用的实用程序类,但它确实是。它甚至比 更强大ServiceLoader
,因为它允许对返回的提供程序的顺序进行一些控制并直接访问注册表。
See http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html
请参阅http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html
回答by Petrychenko
Unfortunately,
很遗憾,
There's nothing built into Java 1.5 for this ...
Java 1.5 没有为此内置任何东西......
is only a part of truth.
只是真理的一部分。
There is non-standard sun.misc.Service
around.
sun.misc.Service
周围有非标准。
http://www.docjar.com/docs/api/sun/misc/Service.html
http://www.docjar.com/docs/api/sun/misc/Service.html
Beware, it is not a part of standard J2SE API!
It is non-standard part of Sun JDK.
So you can not rely on it if you use, say, JRockit
.
请注意,它不是标准 J2SE API 的一部分!它是 Sun JDK 的非标准部分。因此,如果您使用例如JRockit
.
回答by Adam Gent
This is an old question but the other option is to use Package Level Annotations. See my answer for: Find Java classes implementing an interface
这是一个老问题,但另一种选择是使用Package Level Annotations。请参阅我的答案:查找实现接口的 Java 类
Package level annotations are annotations that are in package-info.java classes.
包级别注释是位于 package-info.java 类中的注释。
JAXB uses this instead of Service Loaders. I also think its more flexible than the service loader.
JAXB 使用它而不是服务加载器。我也认为它比服务加载器更灵活。