15

定義されたインターフェイスを実装するクラスパスで実行時にクラスを検出するにはどうすればよいですか?

ServiceLoader は適しています (私は使用していないと思います) が、Java 1.5 で行う必要があります。

4

6 に答える 6

19

このための Java 1.5 には何も組み込まれていません。私はそれを自分で実装しました。それほど複雑ではありません。ただし、Java 6 にアップグレードするときは、実装への呼び出しを への呼び出しに置き換える必要がありますServiceLoader。アプリとローダーの間に小さなブリッジを定義することもできましたが、それを使用する場所はわずかであり、ラッパー自体は ServiceLoader の有力な候補となります。

これが核となるアイデアです:

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

より良い例外処理は、読者の課題として残されています。また、メソッドをパラメータ化して、呼び出し元が選択した ClassLoader を受け入れることもできます。

于 2008-10-30T20:41:22.017 に答える
6

javax.imageio.spi.ServiceRegistry is the equivalent with prior Java versions. It's available since 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.

See http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html

于 2011-03-09T13:53:15.800 に答える
1

ServiceLoaderは非常に基本的なものであり、1.3以降JDK内で(非公式に)使用されています。ServiceLoaderはついにそれを一級市民にしました。インターフェイスに名前が付けられたリソースファイルを検索するだけです。このファイルは、基本的にライブラリjarのMETA-INFディレクトリにバンドルされています。

そのファイルには、ロードするクラスの名前が含まれています。

したがって、次の名前のファイルがあります。

META-INF / services / com.example.your.interface

その中には、com.you.your.interfaceImplという1行があります。

ServiceLoaderの代わりに、NetbeansLookupが好きです。1.5(そしておそらく1.4)で動作します。

箱から出して、ServiceLoaderとまったく同じことを実行し、使用するのは簡単です。しかし、それははるかに多くの柔軟性を提供します。

リンクは次のとおりです:http://openide.netbeans.org/lookup/

これがServiceLoaderに関する記事ですが、下部にNetbeansルックアップが記載されています: http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html

于 2008-10-30T21:21:13.777 に答える
1

不運にも、

このためにJava1.5に組み込まれているものは何もありません...

真実の一部にすぎません。

sun.misc.Service周りに非標準があります。

http://www.docjar.com/docs/api/sun/misc/Service.html

注意してください、それは標準のJ2SE APIの一部ではありません!これはSunJDKの非標準部分です。したがって、たとえば、を使用する場合は、これに依存することはできませんJRockit

于 2011-06-30T11:47:57.477 に答える
1

これは古い質問ですが、他のオプションはPackage Level Annotationsを使用することです。私の答えを参照してください:インターフェースを実装する Java クラスを見つける

パッケージ レベルの注釈は、package-info.java クラスにある注釈です。

JAXB は、サービス ローダーの代わりにこれを使用します。また、サービスローダーよりも柔軟だと思います。

于 2011-09-14T20:44:37.737 に答える
0

クラスパスに含まれるクラスを確実に知る方法はありません。そのドキュメントによると、ServiceLoader は外部ファイルに依存して、ロードするクラスを伝えます。同じことをしたいかもしれません。基本的な考え方は、ロードするクラスの名前を持つファイルを用意し、リフレクションを使用してそれ/それらをインスタンス化することです。

于 2008-10-30T20:34:27.290 に答える