282

注釈付きクラスのクラスパス全体を検索するにはどうすればよいですか?

私はライブラリを作成していて、ユーザーがクラスに注釈を付けられるようにしたいので、Web アプリケーションの開始時にクラスパス全体をスキャンして特定の注釈を探す必要があります。

Java EE 5 Web サービスまたは EJB の新機能のようなものを考えています。@WebServiceクラスにorで注釈を付ける@EJBと、システムはロード中にこれらのクラスを見つけて、リモートでアクセスできるようにします。

4

13 に答える 13

234

org.springframework.context.annotation.ClassPathScanningCandidateComponentProviderを使用する

API

基本パッケージからクラスパスをスキャンするコンポーネント プロバイダー。次に、除外フィルターと包含フィルターを結果のクラスに適用して、候補を見つけます。

ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(<DO_YOU_WANT_TO_USE_DEFALT_FILTER>);

scanner.addIncludeFilter(new AnnotationTypeFilter(<TYPE_YOUR_ANNOTATION_HERE>.class));

for (BeanDefinition bd : scanner.findCandidateComponents(<TYPE_YOUR_BASE_PACKAGE_HERE>))
    System.out.println(bd.getBeanClassName());
于 2009-09-12T15:11:38.583 に答える
155

そして別の解決策は、ronmamo の Reflectionsです。

簡単なレビュー:

  • Spring を使用している場合は、Spring ソリューションが最適です。そうでなければ、それは大きな依存関係です。
  • ASM を直接使用するのは少し面倒です。
  • Java Assist を直接使用するのも扱いにくいです。
  • Annovention は超軽量で便利です。Maven 統合はまだありません。
  • Reflections はすべてのインデックスを作成し、超高速です。
于 2010-08-02T21:08:47.923 に答える
44

ClassGraphを使用して任意のアノテーションを持つクラスを検索したり、特定のインターフェイスを実装するクラスなど、他の関心のある基準を検索したりできます。(免責事項、私は ClassGraph の作成者です。) ClassGraph は、クラス グラフ全体 (すべてのクラス、注釈、メソッド、メソッド パラメーター、およびフィールド) の抽象表現をメモリ内、クラスパス上のすべてのクラス、またはクラスパス内のクラスに対して構築できます。ホワイトリストに登録されたパッケージであり、必要に応じてそのクラス グラフを照会できます。ClassGraph は、他のどのスキャナーよりも多くのクラスパス指定メカニズムとクラスローダーをサポートし、新しい JPMS モジュール システムともシームレスに動作するため、コードを ClassGraph に基づいて作成すると、コードの移植性が最大限に高まります。ここで API を参照してください。

于 2014-08-17T22:53:25.263 に答える
27

本当に軽量(依存関係なし、シンプルな API、15 kb の jar ファイル) で非常に高速なソリューションが必要な場合は、annotation-detectorhttps ://github.com/rmuller/infomas-aslを参照してください。

免責事項: 私は著者です。

于 2011-11-21T09:05:47.840 に答える
20

Java Pluggable Annotation Processing API を使用して、コンパイル プロセス中に実行されるアノテーション プロセッサを記述し、すべてのアノテーション付きクラスを収集して、実行時に使用するインデックス ファイルを構築できます。

これは、実行時にクラスパスをスキャンする必要がないため、アノテーション付きクラスの検出を実行できる最速の方法です。これは通常、非常に遅い操作です。また、このアプローチは、ランタイム スキャナで通常サポートされる URLClassLoaders だけでなく、任意のクラスローダーで機能します。

上記のメカニズムは、ClassIndexライブラリに既に実装されています。

これを使用するには、カスタム アノテーションに@IndexAnnotatedメタアノテーションを付けます。これにより、コンパイル時にインデックス ファイルが作成されます: META-INF/annotations/com/test/YourCustomAnnotation には、すべての注釈付きクラスがリストされています。次のコマンドを実行すると、実行時にインデックスにアクセスできます。

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)
于 2011-12-27T08:31:28.297 に答える
5

答えるのが遅すぎますか。ClassPathScanningCandidateComponentProviderScannotationsなどのライブラリを使用する方がよいと思います

しかし、誰かが classLoader を使って試してみたいと思った後でも、パッケージ内のクラスから注釈を出力するために自分でいくつか書きました。

public class ElementScanner {

public void scanElements(){
    try {
    //Get the package name from configuration file
    String packageName = readConfig();

    //Load the classLoader which loads this class.
    ClassLoader classLoader = getClass().getClassLoader();

    //Change the package structure to directory structure
    String packagePath  = packageName.replace('.', '/');
    URL urls = classLoader.getResource(packagePath);

    //Get all the class files in the specified URL Path.
    File folder = new File(urls.getPath());
    File[] classes = folder.listFiles();

    int size = classes.length;
    List<Class<?>> classList = new ArrayList<Class<?>>();

    for(int i=0;i<size;i++){
        int index = classes[i].getName().indexOf(".");
        String className = classes[i].getName().substring(0, index);
        String classNamePath = packageName+"."+className;
        Class<?> repoClass;
        repoClass = Class.forName(classNamePath);
        Annotation[] annotations = repoClass.getAnnotations();
        for(int j =0;j<annotations.length;j++){
            System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
        }
        classList.add(repoClass);
    }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

/**
 * Unmarshall the configuration file
 * @return
 */
public String readConfig(){
    try{
        URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
        JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
         Unmarshaller um =  jContext.createUnmarshaller();
         RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
         return rc.getRepository().getPackageName();
        }catch(Exception e){
            e.printStackTrace();
        }
    return null;

}
}

そして構成ファイルに、パッケージ名を入れて、クラスにアンマーシャリングします。

于 2017-11-22T06:53:43.923 に答える
2

Spring では、AnnotationUtils クラスを使用して次のように記述することもできます。すなわち:

Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);

詳細とすべての異なる方法については、公式ドキュメントを確認してください: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html

于 2015-10-12T23:41:55.623 に答える
2

Classloader API には「enumerate」メソッドがありません。これは、クラスのロードが「オンデマンド」アクティビティであるためです。通常、クラスパスには数千のクラスがあり、必要になるのはそのうちのほんの一部だけです (rt.jarそれだけで、最近では 48MB です!)。

そのため、すべてのクラスを列挙できたとしても、非常に時間とメモリを消費します。

簡単な方法は、関連するクラスをセットアップ ファイル (xml または好みに合わせて何でも) にリストすることです。これを自動的に行いたい場合は、1 つの JAR または 1 つのクラス ディレクトリに制限してください。

于 2008-11-03T17:24:19.180 に答える
1

Google Reflectionsは Spring よりもはるかに高速のようです。この違いに対処するこの機能リクエストを見つけました: http://www.opensaga.org/jira/browse/OS-738

これが、アプリケーションの起動時間が開発中に非常に重要であるため、リフレクションを使用する理由です。リフレクションは、私のユースケースでも非常に使いやすいようです (インターフェースのすべての実装者を見つけます)。

于 2012-07-14T18:37:20.040 に答える
1

リフレクションに代わるものを探しているなら、Panda Utilities - AnnotationsScannerをお勧めします。リフレクション ライブラリのソース コードに基づいた Guava フリー (Guava は ~3MB、Panda Utilities は ~200kb) スキャナです。

また、未来ベースの検索専用です。含まれているソースを複数回スキャンしたり、現在のクラスパスをスキャンできる API を提供したりしたい場合は、AnnotationsScannerProcessすべての fetchedClassFilesをキャッシュするので、非常に高速です。

簡単なAnnotationsScanner使用例:

AnnotationsScanner scanner = AnnotationsScanner.createScanner()
        .includeSources(ExampleApplication.class)
        .build();

AnnotationsScannerProcess process = scanner.createWorker()
        .addDefaultProjectFilters("net.dzikoysk")
        .fetch();

Set<Class<?>> classes = process.createSelector()
        .selectTypesAnnotatedWith(AnnotationTest.class);
于 2018-08-14T13:02:16.637 に答える