1. Introduction
1.简介
The Reflections library works as a classpath scanner. It indexes the scanned metadata and allows us to query it at runtime. It can also save this information, so we can collect and use it at any point during our project, without having to re-scan the classpath again.
Reflections库作为一个classpath扫描仪工作。它对扫描到的元数据进行索引,并允许我们在运行时对其进行查询。它还可以保存这些信息,因此我们可以在项目的任何时候收集和使用这些信息,而不必再次重新扫描classpath。
In this tutorial, we’ll show how to configure the Reflections library and use it in our Java projects.
在本教程中,我们将展示如何配置Reflections库并在我们的Java项目中使用它。
2. Maven Dependency
2.Maven的依赖性
To use Reflections, we need to include its dependency in our project:
要使用Reflections,我们需要在我们的项目中包含其依赖性。
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
We can find the latest version of the library on Maven Central.
我们可以在Maven中心找到该库的最新版本,。
3. Configuring Reflections
3.配置反射
Next, we need to configure the library. The main elements of the configuration are the URLs and scanners.
接下来,我们需要配置该库。配置的主要元素是URLs和扫描器。
The URLs tell the library which parts of the classpath to scan, whereas the scanners are the objects that scan the given URLs.
URLs告诉库要扫描classpath的哪些部分,而扫描器是扫描给定URLs的对象。
In the event that no scanner is configured, the library uses TypeAnnotationsScanner and SubTypesScanner as the default ones.
如果没有配置扫描仪,该库使用TypeAnnotationsScanner和SubTypesScanner作为默认的扫描仪。
3.1. Adding URLs
3.1.添加URL
We can configure Reflections either by providing the configuration’s elements as the varargs constructor’s parameters, or by using the ConfigurationBuilder object.
我们可以通过提供配置的元素作为varargs构造函数的参数,或者使用ConfigurationBuilder对象来配置Reflections。
For instance, we can add URLs by instantiating Reflections using a String representing the package name, the class, or the class loader:
例如,我们可以通过使用代表包名、类或类加载器的String来实例化Reflections来添加URLs。
Reflections reflections = new Reflections("com.baeldung.reflections");
Reflections reflections = new Reflections(MyClass.class);
Reflections reflections = new Reflections(MyClass.class.getClassLoader());
Moreover, because Reflections has a varargs constructor, we can combine all the above configurations’ types to instantiate it:
此外,因为Reflections有一个varargs构造函数,我们可以结合所有上述配置的类型来实例化它。
Reflections reflections = new Reflections("com.baeldung.reflections", MyClass.class);
Here, we are adding URLs by specifying the package and the class to scan.
在这里,我们通过指定扫描的包和类来添加URL。
We can achieve the same results by using the ConfigurationBuilder:
我们可以通过使用ConfigurationBuilder实现同样的结果。
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.baeldung.reflections"))));
Together with the forPackage() method, ClasspathHelper provides other methods, such as forClass() and forClassLoader(), to add URLs to the configuration.
与forPackage()方法一起,ClasspathHelper提供了其他方法,例如forClass()和forClassLoader(),以便将URL添加到配置中。
3.2. Adding Scanners
3.2.添加扫描器
The Reflections library comes with many built-in scanners:
Reflections库带有许多内置的扫描器:。
- FieldAnnotationsScanner – looks for field’s annotations
- MethodParameterScanner – scans methods/constructors, then indexes parameters, and returns type and parameter annotations
- MethodParameterNamesScanner – inspects methods/constructors, then indexes parameter names
- TypeElementsScanner – examines fields and methods, then stores the fully qualified name as a key, and elements as values
- MemberUsageScanner – scans methods/constructors/fields usages
- TypeAnnotationsScanner – looks for class’s runtime annotations
- SubTypesScanner – searches for super classes and interfaces of a class, allowing a reverse lookup for subtypes
- MethodAnnotationsScanner – scans for method’s annotations
- ResourcesScanner – collects all non-class resources in a collection
We can add scanners to the configuration as parameters of Reflections‘ constructor.
我们可以将扫描仪作为Reflections‘构造函数的参数添加到配置中。
For instance, let’s add the first two scanners from the above list:
例如,让我们从上面的列表中添加前两个扫描仪。
Reflections reflections = new Reflections("com.baeldung.reflections"),
new FieldAnnotationsScanner(),
new MethodParameterScanner());
Again, the two scanners can be configured by using the ConfigurationBuilder helper class:
同样,可以通过使用ConfigurationBuilder帮助类来配置这两个扫描仪。
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.baeldung.reflections"))
.setScanners(new FieldAnnotationsScanner(), new MethodParameterScanner()));
3.3. Adding the ExecutorService
3.3.添加ExecutorService
In addition to URLs and scanners, Reflections gives us the possibility to asynchronously scan the classpath by using the ExecutorService.
除了URL和扫描器之外,Reflections给我们提供了通过使用ExecutorService异步扫描classpath的可能性。
We can add it as a parameter of Reflections‘ constructor, or through the ConfigurationBuilder:
我们可以把它作为Reflections的构造函数的一个参数,或者通过ConfigurationBuilder添加。
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.baeldung.reflections"))
.setScanners(new SubTypesScanner(), new TypeAnnotationsScanner())
.setExecutorService(Executors.newFixedThreadPool(4)));
Another option is to simply call the useParallelExecutor() method. This method configures a default FixedThreadPool ExecutorService with a size equal to the number of the available core processors.
另一个选择是简单地调用useParallelExecutor()方法。这个方法配置了一个默认的FixedThreadPool ExecutorService,其大小等于可用的核心处理器数量。
3.4. Adding Filters
3.4.添加过滤器
Another important configurations element is a filter. A filter tells the scanners what to include, and what to exclude, when scanning the classpath.
另一个重要的配置元素是过滤器。过滤器告诉扫描器在扫描classpath时要包括什么,排除什么。
As an illustration, we can configure the filter to exclude scanning of the test package:
作为一个例子,我们可以将过滤器配置为排除对测试包的扫描。
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")));
Now, up to this point, we’ve made a quick overview of the different elements of Reflections‘ configuration. Next, we’ll see how to use the library.
现在,到此为止,我们已经对Reflections的配置的不同元素做了一个快速的概述。接下来,我们将看到如何使用这个库。
4. Querying Using Reflections
4.使用反射法进行查询
After calling one of the Reflections constructors, the configured scanners scan all the provided URLs. Then, for each scanner, the library puts the results in Multimap stores. As a result, in order to use Reflections, we need to query these stores by calling the provided query methods.
在调用其中一个Reflections构造函数后,配置的扫描器会扫描所有提供的URL。然后,对于每个扫描器,库将结果放在Multimap存储中。因此,为了使用Reflections,我们需要通过调用提供的查询方法来查询这些存储。
Let’s see some examples of these query methods.
让我们看看这些查询方法的一些例子。
4.1. Subtypes
4.1.子类型
Let’s start by retrieving all the scanners provided by Reflections:
让我们从检索所有由Reflections提供的扫描仪开始。
public Set<Class<? extends Scanner>> getReflectionsSubTypes() {
Reflections reflections = new Reflections(
"org.reflections", new SubTypesScanner());
return reflections.getSubTypesOf(Scanner.class);
}
4.2. Annotated Types
4.2.注释的类型
Next, we can get all the classes and interfaces that implement a given annotation.
接下来,我们可以得到所有实现某个注解的类和接口。
So, let’s retrieve all the functional interfaces of the java.util.function package:
所以,让我们检索一下java.util.function包的所有功能接口。
public Set<Class<?>> getJDKFunctinalInterfaces() {
Reflections reflections = new Reflections("java.util.function",
new TypeAnnotationsScanner());
return reflections.getTypesAnnotatedWith(FunctionalInterface.class);
}
4.3. Annotated Methods
4.3.注释的方法
Now, let’s use the MethodAnnotationsScanner to get all the methods annotated with a given annotation:
现在,让我们使用MethodAnnotationsScanner来获取所有带有给定注解的方法。
public Set<Method> getDateDeprecatedMethods() {
Reflections reflections = new Reflections(
"java.util.Date",
new MethodAnnotationsScanner());
return reflections.getMethodsAnnotatedWith(Deprecated.class);
}
4.4. Annotated Constructors
4.4.注释的构造函数
Also, we can get all the deprecated constructors:
此外,我们还可以得到所有废弃的构造函数。
public Set<Constructor> getDateDeprecatedConstructors() {
Reflections reflections = new Reflections(
"java.util.Date",
new MethodAnnotationsScanner());
return reflections.getConstructorsAnnotatedWith(Deprecated.class);
}
4.5. Methods’ Parameters
4.5.方法的参数
Additionally, we can use MethodParameterScanner to find all the methods with a given parameter type:
此外,我们可以使用MethodParameterScanner来找到所有具有给定参数类型的方法。
public Set<Method> getMethodsWithDateParam() {
Reflections reflections = new Reflections(
java.text.SimpleDateFormat.class,
new MethodParameterScanner());
return reflections.getMethodsMatchParams(Date.class);
}
4.6. Methods’ Return Type
4.6.方法的返回类型
Furthermore, we can also use the same scanner to get all the methods with a given return type.
此外,我们还可以使用相同的扫描器来获得所有具有给定返回类型的方法。
Let’s imagine that we want to find all the methods of the SimpleDateFormat that return void:
让我们设想一下,我们想找到SimpleDateFormat的所有方法,这些方法返回void。
public Set<Method> getMethodsWithVoidReturn() {
Reflections reflections = new Reflections(
"java.text.SimpleDateFormat",
new MethodParameterScanner());
return reflections.getMethodsReturn(void.class);
}
4.7. Resources
4.7.资源
Finally, let’s use the ResourcesScanner to look for a given filename in our classpath:
最后,让我们使用ResourcesScanner在classpath中寻找一个给定的文件名。
public Set<String> getPomXmlPaths() {
Reflections reflections = new Reflections(new ResourcesScanner());
return reflections.getResources(Pattern.compile(".*pom\\.xml"));
}
4.8. Additional Query Methods
4.8.其他查询方法
The above were but a handful of examples showing how to use Reflections’ query methods. Yet, there are other query methods that we haven’t covered here:
以上只是展示如何使用Reflections的查询方法的少数几个例子。然而,还有其他的查询方法,我们在这里没有涉及。
- getMethodsWithAnyParamAnnotated
- getConstructorsMatchParams
- getConstructorsWithAnyParamAnnotated
- getFieldsAnnotatedWith
- getMethodParamNames
- getConstructorParamNames
- getFieldUsage
- getMethodUsage
- getConstructorUsage
5. Integrating Reflections into a Build Lifecycle
5.将Reflections整合到构建生命周期中
We can easily integrate Reflections into our Maven build using the gmavenplus-plugin.
我们可以使用gmavenplus-plugin,轻松将Reflections集成到Maven构建中。
Let’s configure it to save the result of scans to a file:
让我们把它配置为把扫描结果保存到一个文件中。
<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>
Later on, by calling the collect() method, we can retrieve the saved results and make them available for further use, without having to perform a new scan:
稍后,通过调用collect()方法,我们可以检索保存的结果 并使其可供进一步使用,而不需要执行新的扫描:。
Reflections reflections
= isProduction() ? Reflections.collect() : new Reflections("com.baeldung.reflections");
6. Conclusion
6.结语
In this article, we explored the Reflections library. We covered different configuration elements and their usages. And, finally, we saw how to integrate Reflections into a Maven project’s build lifecycle.
在这篇文章中,我们探讨了Reflections库。我们介绍了不同的配置元素及其使用方法。最后,我们看到了如何将Reflections集成到Maven项目的构建生命周期中。
As always, the complete code is available over on GitHub.
一如既往,完整的代码可以在GitHub上获得。