1

実行時にプラグインをロードできる Web アプリケーションに取り組んでいます。OSGi がこれに対する洗練されたソリューションであることは承知していますが、GWT が使用されているため、OSGi への移行は見られません。

プラグインを実装するために、3 つの jar があります: アプリケーション、pluginAPI :

public interface NotificationPlugin {

   public String getName();
}

そして plugin.jar

public class Plugin implements NotificationPlugin {
   private final String PLUGIN_NAME = "Plugin";    
   @Override 
   public String getName() {
       return PLUGIN_NAME;
   }
}

plugin.jar と Web アプリケーションには、pluginapi.jar への依存関係があります。アプリケーションでは、各 jar ファイルを個別の URLClassloader でロードするため、個別にアンロードできます。

    service.setUcl(new URLClassLoader(url));

    ServiceLoader<NotificationPlugin> sl = ServiceLoader.load(NotificationPlugin.class, service.getUcl());
    Iterator<NotificationPlugin> apit = sl.iterator();
    service.setPlugin(apit.next());

    while (apit.hasNext()) {
            System.out.println(apit.next().getClass().getName());
        }  

上記のコード スニペットは、アプリケーション サーバーの外部でコードを実行した場合にのみ、魔法のように機能します。Jetty を使用して netbeans で GWT をデバッグしており、アプリケーションは Tomcat にデプロイされています (どちらも同じ動作を示します)。アプリケーション サーバーでコードを実行するとすぐに、コードは ServiceLoader.java のこの時点で失敗します。

public S next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        String cn = nextName;
        nextName = null;
        Class<?> c = null;
        try {
            c = Class.forName(cn, false, loader);
        } catch (ClassNotFoundException x) {
            fail(service,
                 "Provider " + cn + " not found");
        }
 --->   if (!service.isAssignableFrom(c)) {   <-----
            fail(service,
                 "Provider " + cn  + " not a subtype");
        }
        try {
            S p = service.cast(c.newInstance());
            providers.put(cn, p);
            return p;
        } catch (Throwable x) {
            fail(service,
                 "Provider " + cn + " could not be instantiated: " + x,
                 x);
        }
        throw new Error();          // This cannot happen
    }

私の意見では、プラグインとインターフェースの両方が適切にロードされていることをデバッグが示しています。それ以外の場合、Class.forName は失敗します。繰り返しますが、これはアプリケーション サーバーがなければ実現しません。サービス情報は META-INF/services/xx.xx.pluginapi.NotificationPlugin にあります。

私の直感によると、エラーはアプリケーション サーバーが ClassLoaders を使用する方法と関係がありますが、私と Google は参照を見つけることができませんでした。この問題を克服する方法を知っている人はいますか?助けていただければ幸いです。

4

2 に答える 2