1. 简介
Reflections 是一个强大的类路径扫描器。它会扫描并索引元数据,支持在运行时进行查询。此外,还可以将扫描结果保存下来,这样在整个项目生命周期中可以随时复用这些信息,而无需重复扫描类路径。
本文将带你了解如何在 Java 项目中配置和使用 Reflections 库。
2. Maven 依赖
要使用 Reflections,首先需要添加其 Maven 依赖:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
你可以在 Maven Central 找到最新的版本。
3. 配置 Reflections
配置 Reflections 主要涉及两个核心部分:URL 和扫描器(Scanner)。
- URL:指定类路径的哪些部分需要被扫描。
- Scanner:负责实际执行扫描任务的对象。
如果没有显式配置扫描器,Reflections 默认使用 TypeAnnotationsScanner
和 SubTypesScanner
。
3.1. 添加 URL
可以通过构造函数参数或使用 ConfigurationBuilder
来配置 Reflections。
例如,通过包名、类或类加载器实例化 Reflections:
Reflections reflections = new Reflections("com.baeldung.reflections");
Reflections reflections = new Reflections(MyClass.class);
Reflections reflections = new Reflections(MyClass.class.getClassLoader());
由于构造函数支持可变参数,也可以组合使用多种方式:
Reflections reflections = new Reflections("com.baeldung.reflections", MyClass.class);
使用 ConfigurationBuilder
也能达到相同效果:
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.baeldung.reflections"))));
除了 forPackage()
,ClasspathHelper
还提供了 forClass()
和 forClassLoader()
等方法来添加 URL。
3.2. 添加扫描器(Scanner)
✅ Reflections 提供了多个内置扫描器:
FieldAnnotationsScanner
– 扫描字段上的注解MethodParameterScanner
– 扫描方法/构造函数参数、返回值类型和参数注解MethodParameterNamesScanner
– 获取方法/构造函数的参数名称TypeElementsScanner
– 扫描字段和方法,以全限定类名为键存储元素MemberUsageScanner
– 扫描成员(方法/字段等)的使用情况TypeAnnotationsScanner
– 扫描类上的运行时注解SubTypesScanner
– 扫描类的父类和接口,支持反向查找子类型MethodAnnotationsScanner
– 扫描方法上的注解ResourcesScanner
– 收集所有非类资源文件
可以通过构造函数或 ConfigurationBuilder
添加扫描器:
Reflections reflections = new Reflections("com.baeldung.reflections"),
new FieldAnnotationsScanner(),
new MethodParameterScanner());
或者使用 ConfigurationBuilder
:
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.baeldung.reflections"))
.setScanners(new FieldAnnotationsScanner(), new MethodParameterScanner()));
3.3. 使用 ExecutorService 实现异步扫描
除了 URL 和 Scanner,还可以使用 ExecutorService
实现并发扫描:
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.baeldung.reflections"))
.setScanners(new SubTypesScanner(), new TypeAnnotationsScanner())
.setExecutorService(Executors.newFixedThreadPool(4)));
也可以直接调用 .useParallelExecutor()
方法,默认会根据 CPU 核心数创建固定线程池。
3.4. 添加过滤器
过滤器用于控制哪些类应该被包含或排除在扫描之外。比如排除测试包:
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.baeldung.reflections"))
.setScanners(new SubTypesScanner(), new TypeAnnotationsScanner())
.filterInputsBy(new FilterBuilder().excludePackage("com.baeldung.reflections.test")));
到这里,我们已经完成了 Reflections 的基本配置,接下来是实际使用阶段。
4. 查询功能详解
调用 Reflections 构造函数后,扫描器会扫描对应的 URL,并将结果存储在 Multimap 中。我们可以使用 Reflections 提供的查询方法来访问这些数据。
4.1. 查找子类型
获取某个类的所有子类:
public Set<Class<? extends Scanner>> getReflectionsSubTypes() {
Reflections reflections = new Reflections(
"org.reflections", new SubTypesScanner());
return reflections.getSubTypesOf(Scanner.class);
}
4.2. 查找带特定注解的类
获取带有某注解的所有类:
public Set<Class<?>> getJDKFunctinalInterfaces() {
Reflections reflections = new Reflections("java.util.function",
new TypeAnnotationsScanner());
return reflections.getTypesAnnotatedWith(FunctionalInterface.class);
}
4.3. 查找带特定注解的方法
使用 MethodAnnotationsScanner
查找方法:
public Set<Method> getDateDeprecatedMethods() {
Reflections reflections = new Reflections(
"java.util.Date",
new MethodAnnotationsScanner());
return reflections.getMethodsAnnotatedWith(Deprecated.class);
}
4.4. 查找带特定注解的构造函数
public Set<Constructor> getDateDeprecatedConstructors() {
Reflections reflections = new Reflections(
"java.util.Date",
new MethodAnnotationsScanner());
return reflections.getConstructorsAnnotatedWith(Deprecated.class);
}
4.5. 查找特定参数类型的方法
public Set<Method> getMethodsWithDateParam() {
Reflections reflections = new Reflections(
java.text.SimpleDateFormat.class,
new MethodParameterScanner());
return reflections.getMethodsMatchParams(Date.class);
}
4.6. 查找特定返回值类型的方法
public Set<Method> getMethodsWithVoidReturn() {
Reflections reflections = new Reflections(
"java.text.SimpleDateFormat",
new MethodParameterScanner());
return reflections.getMethodsReturn(void.class);
}
4.7. 查找资源文件
使用 ResourcesScanner
搜索 classpath 下的资源:
public Set<String> getPomXmlPaths() {
Reflections reflections = new Reflections(new ResourcesScanner());
return reflections.getResources(Pattern.compile(".*pom\\.xml"));
}
4.8. 其他常用查询方法
✅ Reflections 还提供以下查询方法(这里列出部分):
getMethodsWithAnyParamAnnotated
getConstructorsMatchParams
getConstructorsWithAnyParamAnnotated
getFieldsAnnotatedWith
getMethodParamNames
getConstructorParamNames
getFieldUsage
getMethodUsage
getConstructorUsage
5. 将 Reflections 集成到构建流程中
我们可以使用 gmavenplus-plugin 将 Reflections 集成到 Maven 构建过程中,并将扫描结果保存为文件:
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<scripts>
<script><![CDATA[
new org.reflections.Reflections(
"com.baeldung.refelections")
.save("${outputDirectory}/META-INF/reflections/reflections.xml")]]>
</script>
</scripts>
</configuration>
</execution>
</executions>
</plugin>
之后,在运行时可以通过 collect()
方法加载已保存的结果,避免重新扫描:
Reflections reflections
= isProduction() ? Reflections.collect() : new Reflections("com.baeldung.reflections");
⚠️ 注意:isProduction()
是自定义逻辑,用于判断是否处于生产环境。
6. 总结
在这篇文章中,我们介绍了 Reflections 库的核心功能与配置方式,包括 URL 设置、Scanner 配置、过滤器以及如何将其集成进 Maven 构建流程。
总的来说,Reflections 是一个非常实用的工具库,特别适合需要动态扫描类路径并处理元数据的场景。
完整代码示例可在 GitHub 获取。