回答:
使用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());
@Conditional
アノテーションに基づいて評価および動作します。したがって、クラスの@Conditional
値がfalseを返しfindCandidateComponents
ている場合、スキャナーのフィルターに一致していても、によって返されません。これは今日私を投げました-私は代わりに以下のジョナサンのソリューションを使用することになりました。
BeanDefinition
オブジェクトはクラスを直接取得する方法を提供していません。最も近いものgetBeanClassName
は、完全修飾クラス名を返すようですが、このメソッドの正確な動作は明確ではありません。また、クラスが見つかったクラスローダーは明確ではありません
Class<?> cl = Class.forName(beanDef.getBeanClassName());
farenda.com/spring/find-annotated-classes
そして別の解決策はGoogleの反射ですです。
簡単なレビュー:
new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)
。c'est売り込み。
ClassGraphを使用して、特定の注釈が付いたクラスを検索したり、特定のインターフェースを実装するクラスなど、関心のある他の基準を検索したりできます。(免責事項、私はClassGraphの作成者です。)ClassGraphは、メモリ内、クラスパス上のすべてのクラス、またはホワイトリストに登録されたパッケージを使用して、必要に応じてクラスグラフをクエリできます。ClassGraphは、他のどのスキャナーよりも多くのクラスパス仕様メカニズムとクラスローダーをサポートし、新しいJPMSモジュールシステムとシームレスに連携するため、コードをClassGraphに基づいている場合、コードは最大限に移植可能になります。こちらのAPIをご覧ください。
Reflections
ます。また、グアバなどを使用していて、コレクションを簡単に変更したい場合も簡単です。内部にも素晴らしいコメント。
本当に軽量(依存関係なし、シンプルなAPI、15 kbのjarファイル)で非常に高速なソリューションが必要な場合はannotation-detector
、https://github.com/rmuller/infomas-aslにある以下を参照してください。
免責事項:私は著者です。
Java Pluggable Annotation Processing APIを使用して、コンパイルプロセス中に実行され、すべての注釈付きクラスを収集し、ランタイムで使用するインデックスファイルを構築する注釈プロセッサを作成できます。
これは、実行時にクラスパスをスキャンする必要がないため、注釈付きのクラス検出を行うための可能な最速の方法です。これは通常、非常に遅い操作です。また、このアプローチは、ランタイムスキャナーで通常サポートされているURLClassLoadersだけでなく、あらゆるクラスローダーで機能します。
上記のメカニズムは、ClassIndexライブラリにすでに実装されています。
これを使用するには、@ IndexAnnotatedメタ注釈でカスタム注釈に注釈を付けます。これにより、コンパイル時にインデックスファイルが作成されます。すべての注釈付きクラスをリストするMETA-INF / annotations / com / test / YourCustomAnnotation。次のコマンドを実行すると、実行時にインデックスにアクセスできます。
ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)
答えるには遅すぎますか?ClassPathScanningCandidateComponentProviderやScannotationsのようなライブラリを使用する方が良いと思います
しかし、誰かが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;
}
}
そして、設定ファイルで、パッケージ名を入れてクラスにアンマーシャルします。
Springでは、AnnotationUtilsクラスを使用して次のように記述することもできます。つまり:
Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);
詳細およびすべての異なる方法については、公式ドキュメントを確認してください:https : //docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html
null
、2番目のパラメーター(クラスを定義し、継承階層が注釈を使用するクラスをSpringがスキャンする)として値を指定null
した場合、実装によれば、いつでも元に戻すことができます。
インターフェースも発見したい場合は、Google Reflection。
Spring ClassPathScanningCandidateComponentProvider
はインターフェースを発見していません。
Google ReflectionsはSpringよりもはるかに高速であるようです。この違いに対処するこの機能リクエストが見つかりました:http ://www.opensaga.org/jira/browse/OS-738
アプリケーションの起動時間は開発中に非常に重要であるため、これがReflectionsを使用する理由です。リフレクションは、私のユースケースでも非常に使いやすいようです(インターフェイスのすべての実装者を見つけます)。
リフレクションの代替手段を探している場合は、Panda Utilities-AnnotationsScannerをお勧めします。ます。これは、反射ライブラリのソースコードに基づく、グアバフリー(グアバは最大3MB、パンダユーティリティは最大200kb)スキャナーです。
また、将来に基づく検索専用です。含まれているソースを複数回スキャンしたい場合や、誰かが現在のクラスパスをスキャンできるようにするAPIを提供したい場合AnnotationsScannerProcess
はClassFiles
、フェッチされたすべてをキャッシュするため、非常に高速です。
簡単な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);
春にはAnnotatedTypeScanner
クラスと呼ばれるものがあります。
このクラスは内部で使用します
ClassPathScanningCandidateComponentProvider
このクラスには、クラスパスリソースを実際にスキャンするためのコードがあります。これは、実行時に使用可能なクラスメタデータを使用して行われます。
このクラスを拡張するか、同じクラスをスキャンに使用できます。以下はコンストラクタの定義です。
/**
* Creates a new {@link AnnotatedTypeScanner} for the given annotation types.
*
* @param considerInterfaces whether to consider interfaces as well.
* @param annotationTypes the annotations to scan for.
*/
public AnnotatedTypeScanner(boolean considerInterfaces, Class<? extends Annotation>... annotationTypes) {
this.annotationTypess = Arrays.asList(annotationTypes);
this.considerInterfaces = considerInterfaces;
}