簡體   English   中英

通過java.util.ServiceLoader加載通用服務實現

[英]Loading generic service implementations via 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)並以相同方式更改<T> Service<T> getService(Class<?> t)可以更加動態(我使用后者)對於我自己,因為我在開始時在我的界面上有一個方法boolean canHandle(T t) 。)

這里的問題是服務加載器正在使用列出給定類/接口的所有實現的文件,該文件由接口名稱命名。 沒有預見到將type參數放入此文件名中,並且實際上也不可能將泛型類型作為Class對象傳遞。

所以,你在這里只能得到任何類型的通用服務,然后檢查它們的類對象,看它是否是Service<String>的子類型。

像這樣的東西:

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;
    }

}

這沒有經過測試,可能需要擴展到我們的類直接實現的接口擴展的搜索接口,以及由我們的(通用)超類實現的接口。

當然,這只能找到類似的課程

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

不喜歡

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

其中Example<String>可能是您的服務的有效實現。

您也可以只復制ServiceLoader類文件並從load()方法中刪除泛型類型參數,使其始終有效。 你只需要覆蓋警告。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM