通过 java.util.ServiceLoader 加载通用服务实现
前几天我在使用 java.util.ServiceLoader 时偶然发现了一些不便,并在我心中形成了一些问题。
假设我有一个通用服务:
public interface Service<T> { ... }
我无法明确告诉 ServiceLoader
仅加载具有特定通用类型的实现。
ServiceLoader<Service<String>> services =
ServiceLoader.load(Service.class); // Fail.
我的问题是:使用 ServiceLoader 安全加载通用服务的实现有哪些合理的方法?
在提出上述问题之后,在 Paŭlo 回答之前,我已经想出了一个解决方案。
public interface Service<T> { ...
// true if an implementation can handle the given `t' type; false otherwise.
public boolean canHandle(Class<?> t) { ...
public final class StringService implements Service<String> { ...
@Override public boolean canHandle(Class<?> t) {
if (String.class.isAssignableFrom(type))
return true;
return false;
}
public final class DoubleService implements Service<Double> { ...
// ...
public final class Services { ...
public static <T> Service<T> getService(Class<?> t) {
for (Service<T> s : ServiceLoader.load(Service.class))
if (s.canServe(t))
return s;
throw new UnsupportedOperationException("No servings today my son!");
}
将 boolean canServe(Class t)
更改为 boolean canServe(Object o)
并更改
)开头的界面。)
I've stumbled upon some inconvenience the other day using java.util.ServiceLoader
and some questions formed in me.
Suppose I have a generic service:
public interface Service<T> { ... }
I couldn't explicitly tell ServiceLoader
to load only implementations with a specific generic type.
ServiceLoader<Service<String>> services =
ServiceLoader.load(Service.class); // Fail.
My question is: what are reasonable ways to use ServiceLoader
to safely load implementations of a generic service?
After asking the above question and before Paŭlo's answer I've managed to come up with a solution.
public interface Service<T> { ...
// true if an implementation can handle the given `t' type; false otherwise.
public boolean canHandle(Class<?> t) { ...
public final class StringService implements Service<String> { ...
@Override public boolean canHandle(Class<?> t) {
if (String.class.isAssignableFrom(type))
return true;
return false;
}
public final class DoubleService implements Service<Double> { ...
// ...
public final class Services { ...
public static <T> Service<T> getService(Class<?> t) {
for (Service<T> s : ServiceLoader.load(Service.class))
if (s.canServe(t))
return s;
throw new UnsupportedOperationException("No servings today my son!");
}
Changing boolean canServe(Class<?> t)
to boolean canServe(Object o)
and also changing <T> Service<T> getService(Class<?> t)
in the same manner can be more dynamic (I'm using the latter for myself as I had a method boolean canHandle(T t)
on my interface in the beginning.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里的问题是服务加载器正在使用一个列出给定类/接口的所有实现的文件,该文件由接口名称命名。没有预见到将类型参数放入此文件名中,并且实际上也不可能将泛型类型作为
Class
对象传递。因此,您在这里只能获取任何类型的通用服务,然后检查它们的类对象以查看它是否是
Service
的子类型。像这样的东西:
这没有经过测试,可能需要扩展以搜索由我们的类直接实现的接口扩展的接口,以及由我们的(通用)超类实现的接口。
当然,这只能找到类似于
Example可能是服务的有效实现的类。
The problem here is that the service loader is using a file listing all implementations of a given class/interface, the file being named by the interfaces name. It was not foreseen to put the type parameter into this file name, and it also is not really possible to pass generic types as
Class
objects.So, you here can only get your generic services of any types, and then inspect their class object to see if it is a subtype of
Service<String>
.Something like this:
This is not tested, and may need to be extended to also search interfaces extended by the interfaces our class implements directly, and interfaces implemented by our (generic) superclass.
And of course, this can only find classes like
not something like
where
Example<String>
might be a valid implementation of your service.您还可以只复制 ServiceLoader 类文件并从 load() 方法中删除泛型类型参数,使其始终有效。您只需要忽略这些警告即可。
You could also just copy the ServiceLoader class file and remove the generic type argument from the load() method, causing it to always work. You'll just need to override the warnings.