简体   繁体   English

通过java.util.ServiceLoader加载通用服务实现

[英]Loading generic service implementations via java.util.ServiceLoader

I've stumbled upon some inconvenience the other day using java.util.ServiceLoader and some questions formed in me. 前几天我偶然发现了一些使用java.util.ServiceLoader不便,并在我身上形成了一些问题。

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 加载具有特定泛型类型的实现。

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? 我的问题是:使用ServiceLoader安全加载通用服务的实现的合理方法是什么?


After asking the above question and before Paŭlo's answer I've managed to come up with a solution. 在询问了上述问题之后,在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!");
    }

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.) boolean canServe(Class<?> t)更改为boolean canServe(Object o)并以相同方式更改<T> Service<T> getService(Class<?> t)可以更加动态(我使用后者)对于我自己,因为我在开始时在我的界面上有一个方法boolean canHandle(T t) 。)

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. 没有预见到将type参数放入此文件名中,并且实际上也不可能将泛型类型作为Class对象传递。

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> . 所以,你在这里只能得到任何类型的通用服务,然后检查它们的类对象,看它是否是Service<String>的子类型。

Something like this: 像这样的东西:

class Test{

    public Service<String> getStringService() {
        // it is a bit strange that we can't explicitely construct a
        // parametrized type from raw type and parameters, so here
        // we use this workaround. This may need a dummy method or
        // variable if this method should have another return type.
        ParametrizedType stringServiceType =
            (ParametrizedType)Test.class.getMethod("getStringService").getGenericReturnType();

        ServiceLoader<Service<?>> loader = ServiceLoader.load(Service<?>.class);
        for(Service<?> service : loader) {
           if(isImplementing(service.getClass(), stringServiceType)) {
              @SuppressWarnings("unchecked")
              Service<String> s = (Service)service;
              return s;
           }
        }
    }

    public boolean isImplementing(Class<?> candidate, ParametrizedType t) {
        for(Type iFace : candidate.getGenericInterfaces()) {
           if(iFace.equals(t)) {
              return true;
           }
           if(iFace instanceof ParametrizedType &&
              ((ParametrizedType)iFace).getRawType().equals(t.getRawType())) {
              return false;
           }
        }
        return false;
    }

}

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 当然,这只能找到类似的课程

class Example implements Service<String> { ...}

not something like 不喜欢

class Example<X> implements Service<X> { ... }

where Example<String> might be a valid implementation of your service. 其中Example<String>可能是您的服务的有效实现。

You could also just copy the ServiceLoader class file and remove the generic type argument from the load() method, causing it to always work. 您也可以只复制ServiceLoader类文件并从load()方法中删除泛型类型参数,使其始终有效。 You'll just need to override the warnings. 你只需要覆盖警告。

  public static <S> ServiceLoader load(final Class<S> service)
   {
      return load(service, Thread.currentThread().getContextClassLoader());
   }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 java.util.ServiceLoader只加载一个服务实例 - does java.util.ServiceLoader load only a single instance of a service 使用 java.util.serviceLoader 动态加载多个 jar 文件 - loading multiple jar files dynamically using java.util.serviceLoader java.util.ServiceLoader如何工作? - how java.util.ServiceLoader works? PowerMock:java.lang.IllegalAccessError:模拟java.util.ServiceLoader时的java.lang.Class - PowerMock: java.lang.IllegalAccessError: java.lang.Class when mocking java.util.ServiceLoader 如何阻止maven-shade-plugin阻止opensaml-impl类型的java.util.ServiceLoader初始化 - How to stop maven-shade-plugin from blocking java.util.ServiceLoader initialization of opensaml-impl types Java ServiceLoader:没有错误,但是也没有实现 - Java ServiceLoader: no error, but also no implementations found ServiceLoader 查找接口的实现 - ServiceLoader to find implementations of an interface Java 9 ServiceLoader运行时模块的加载和替换 - Java 9 ServiceLoader runtime module loading and replacement 嵌入式glassfish:java.lang.NoClassDefFoundError:java / util / ServiceLoader - embedded glassfish: java.lang.NoClassDefFoundError: java/util/ServiceLoader 简单ServiceLoader - java.util.ServiceConfigurationError ...找不到提供程序 - Simple ServiceLoader - java.util.ServiceConfigurationError … Provider … not found
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM