在运行时扫描 Java 注释
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/259140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scanning Java annotations at runtime
提问by Alotor
What is the best way of searching the whole classpath for an annotated class?
在整个类路径中搜索带注释的类的最佳方法是什么?
I'm doing a library and I want to allow the users to annotate their classes, so when the Web application starts I need to scan the whole classpath for certain annotation.
我正在做一个库,我想允许用户注释他们的类,所以当 Web 应用程序启动时,我需要扫描整个类路径以获得某些注释。
Do you know a library or a Java facility to do this?
你知道一个库或一个 Java 工具来做到这一点吗?
Edit: I'm thinking about something like the new functionality for Java EE 5 Web Services or EJB's. You annotate your class with @WebService
or @EJB
and the system finds these classes while loading so they are accessible remotely.
编辑:我正在考虑 Java EE 5 Web 服务或 EJB 的新功能。您使用@WebService
or注释您的类,@EJB
系统会在加载时找到这些类,以便远程访问它们。
采纳答案by Arthur Ronald
Use org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
使用org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
API
应用程序接口
A component provider that scans the classpath from a base package. It then applies exclude and include filters to the resulting classes to find candidates.
从基本包扫描类路径的组件提供程序。然后将排除和包含过滤器应用于结果类以查找候选者。
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());
回答by mfx
The Classloader API doesn't have an "enumerate" method, because class loading is an "on-demand" activity -- you usually have thousands of classes in your classpath, only a fraction of which will ever be needed (the rt.jar alone is 48MB nowadays!).
Classloader API 没有“枚举”方法,因为类加载是一种“按需”活动——您的类路径中通常有数千个类,其中只有一小部分是需要的(rt.jar现在仅 48MB!)。
So, even if you couldenumerate all classes, this would be very time- and memory-consuming.
因此,即使您可以枚举所有类,这也将非常耗时和消耗内存。
The simple approach is to list the concerned classes in a setup file (xml or whatever suits your fancy); if you want to do this automatically, restrict yourself to one JAR or one class directory.
简单的方法是在设置文件(xml 或任何适合您喜欢的文件)中列出相关类;如果您想自动执行此操作,请将自己限制在一个 JAR 或一个类目录中。
回答by Jonathan
And another solution is Google reflections.
另一个解决方案是Google 反射。
Quick review:
快速复审:
- Spring solution is the way to go if you're using Spring. Otherwise it's a big dependency.
- Using ASM directly is a bit cumbersome.
- Using Java Assist directly is clunky too.
- Annovention is super lightweight and convenient. No maven integration yet.
- Google reflections pulls in Google collections. Indexes everything and then is super fast.
- 如果您使用的是 Spring,则 Spring 解决方案是可行的方法。否则它是一个很大的依赖。
- 直接使用ASM 有点麻烦。
- 直接使用 Java Assist 也很笨拙。
- Annovention 超轻量级且方便。还没有 Maven 集成。
- 谷歌反射拉入谷歌收藏。索引一切,然后超级快。
回答by rmuller
If you want a really light weight(no dependencies, simple API, 15 kb jar file) and very fastsolution, take a look at annotation-detector
found at https://github.com/rmuller/infomas-asl
如果你想要一个真正重量轻(无依赖性,简单的API,15 kb的jar文件)和非常快的解决方案,来看看annotation-detector
在发现https://github.com/rmuller/infomas-asl
Disclaimer: I am the author.
免责声明:我是作者。
回答by S?awek
You can use Java Pluggable Annotation Processing API to write annotation processor which will be executed during the compilation process and will collect all annotated classes and build the index file for runtime use.
您可以使用 Java Pluggable Annotation Processing API 编写将在编译过程中执行的注解处理器,它将收集所有注解的类并构建索引文件以供运行时使用。
This is the fastest way possible to do annotated class discovery because you don't need to scan your classpath at runtime, which is usually very slow operation. Also this approach works with any classloader and not only with URLClassLoaders usually supported by runtime scanners.
这是进行带注释的类发现的最快方法,因为您不需要在运行时扫描类路径,这通常是非常慢的操作。此外,这种方法适用于任何类加载器,而不仅仅是运行时扫描程序通常支持的 URLClassLoader。
The above mechanism is already implemented in ClassIndexlibrary.
上述机制已经在ClassIndex库中实现。
To use it annotate your custom annotation with @IndexAnnotatedmeta-annotation. This will create at compile time an index file: META-INF/annotations/com/test/YourCustomAnnotation listing all annotated classes. You can acccess the index at runtime by executing:
要使用它,请使用@IndexAnnotated元注释来注释您的自定义注释。这将在编译时创建一个索引文件: META-INF/annotations/com/test/YourCustomAnnotation 列出所有带注释的类。您可以通过执行以下操作在运行时访问索引:
ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)
回答by Martin Aubele
Google Reflectionsseems to be much faster than Spring. Found this feature request that adresses this difference: http://www.opensaga.org/jira/browse/OS-738
Google Reflections似乎比 Spring 快得多。找到了解决此差异的此功能请求:http: //www.opensaga.org/jira/browse/OS-738
This is a reason to use Reflections as startup time of my application is really important during development. Reflections seems also to be very easy to use for my use case (find all implementers of an interface).
这是使用反射的一个原因,因为我的应用程序的启动时间在开发过程中非常重要。对于我的用例(查找接口的所有实现者),反射似乎也很容易使用。
回答by Luke Hutchison
You can find classes with any given annotation with ClassGraph, as well as searching for other criteria of interest, e.g. classes that implement a given interface. (Disclaimer, I am the author of ClassGraph.) ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in whitelisted packages, and you can query that class graph however you want. ClassGraph supports more classpath specification mechanisms and classloadersthan any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.
您可以使用ClassGraph找到具有任何给定注释的类,以及搜索其他感兴趣的标准,例如实现给定接口的类。(免责声明,我是 ClassGraph 的作者。)ClassGraph 可以在内存中、为类路径上的所有类或为类路径中的类构建整个类图(所有类、注释、方法、方法参数和字段)的抽象表示列入白名单的包,您可以根据需要查询该类图。ClassGraph 支持比任何其他扫描器更多的类路径规范机制和类加载器,并且还可以与新的 JPMS 模块系统无缝协作,因此如果您的代码基于 ClassGraph,您的代码将具有最大的可移植性。请参阅此处的 API。
回答by magiccrafter
With Spring you can also just write the following using AnnotationUtils class. i.e.:
使用 Spring,您还可以使用 AnnotationUtils 类编写以下内容。IE:
Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);
For more details and all different methods check official docs: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html
有关更多详细信息和所有不同方法,请查看官方文档:https: //docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html
回答by kenobiwan
Is it too late to answer. I would say, its better to go by Libraries like ClassPathScanningCandidateComponentProvideror like Scannotations
是不是来不及回答了。我会说,最好使用ClassPathScanningCandidateComponentProvider或Scannotations 之类的库
But even after somebody wants to try some hands on it with classLoader, I have written some on my own to print the annotations from classes in a package:
但即使有人想用 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;
}
}
And in config File, you put the package name and unmarshall it to a class .
在 config File 中,您将包名放入并将其解组为 class 。
回答by dzikoysk
If you're looking for an alternative to reflectionsI'd like to recommend Panda Utilities - AnnotationsScanner. It's a Guava-free (Guava has ~3MB, Panda Utilities has ~200kb) scanner based on the reflections library source code.
如果您正在寻找反射的替代方案,我想推荐Panda Utilities - AnnotationsScanner。这是一个基于反射库源代码的无番石榴(番石榴有~3MB,Panda Utilities有~200kb)扫描仪。
It's also dedicated for future-based searches. If you'd like to scan multiple times included sources or even provide an API, which allows someone scanning current classpath, AnnotationsScannerProcess
caches all fetched ClassFiles
, so it's really fast.
它还专用于基于未来的搜索。如果你想多次扫描包含的源,甚至提供一个 API,它允许某人扫描当前的类路径,AnnotationsScannerProcess
缓存所有 fetched ClassFiles
,所以它真的很快。
Simple example of AnnotationsScanner
usage:
简单的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);