Answers:
使用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
,即使它与扫描器的过滤器匹配,也不会由返回。今天,这让我感到震惊-我最终在下面使用了Jonathan的解决方案。
BeanDefinition
对象没有提供直接获取类的方法。最接近的东西似乎是getBeanClassName
返回完全限定的类名,但是此方法的确切行为尚不清楚。此外,还不清楚该类是在哪个类加载器中找到的
Class<?> cl = Class.forName(beanDef.getBeanClassName());
farenda.com/spring/find-annotated-classes
另一个解决方案是Google的思考。
快速复审:
new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)
。吹牛。
您可以使用ClassGraph查找带有任何给定注释的类,以及搜索其他感兴趣的条件,例如实现给定接口的类。(免责声明,我是ClassGraph的作者。)ClassGraph可以为内存中的所有类图(所有类,注释,方法,方法参数和字段),类路径上的所有类或其中的类建立抽象表示。列入白名单的软件包,您可以根据需要查询该类图。与其他任何扫描仪相比,ClassGraph支持更多的类路径规范机制和类加载器,并且还可以与新的JPMS模块系统无缝协作,因此,如果您的代码基于ClassGraph,则代码将具有最大的可移植性。请参阅此处的API。
Reflections
。另外,如果您使用的是番石榴/ etc并想更改其集合,则很容易。里面的评论也很棒。
如果您想要一个非常轻的重量(没有依赖关系,简单的API,15 kb的jar文件)和非常快速的解决方案,请查看annotation-detector
位于https://github.com/rmuller/infomas-asl的内容
免责声明:我是作者。
您可以使用Java Pluggable Annotation Processing API编写注释处理器,该处理器将在编译过程中执行,并将收集所有带注释的类并构建索引文件以供运行时使用。
这是进行带注释的类发现的最快方法,因为您不需要在运行时扫描类路径,这通常是很慢的操作。这种方法也适用于任何类加载器,不仅适用于运行时扫描程序通常支持的URLClassLoader。
上述机制已经在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;
}
}
然后在config File中,将包名称放入并解组到class中。
使用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
值作为第二个参数(定义了类,Spring将在该类中继承层次结构,Spring将在其中扫描使用Annotation的类)null
,那么根据实现,总会得到回报。
如果您也想发现界面,请使用Google Reflection。
Spring ClassPathScanningCandidateComponentProvider
没有发现接口。
Google Reflections似乎比Spring快得多。找到解决此差异的此功能请求:http : //www.opensaga.org/jira/browse/OS-738
这是使用Reflections的原因,因为我的应用程序的启动时间在开发过程中非常重要。在我的用例中,反射似乎也非常易于使用(查找接口的所有实现者)。
如果您正在寻找反射的替代方法,我建议您使用Panda Utilities-AnnotationsScanner。它是基于反射库源代码的无Guava程序(Guava程序约为3MB,Panda Utilities程序约为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;
}