reflections使用总结
本文最后更新于:2022年12月27日 下午
一、项目背景
背景:项目中有解析jar的业务场景,通过解析指定注解标注的class获取指定注解标注的方法
二、reflections能力概览
reflections的部分能力如下
- 类处理
- 获取jar包中的所有class对象
- 获取jar中指定注解的所有class对象
- 获取jar中指定类及其所有的子类的class对象
- …
- 方法处理
- 获取jar包中所有的method对象
- 获取jar中被指定注解标记的method对象
- 获取jar中返回值为指定类的method对象
- 获取jar中入参为指定类的method对象
- …
- 字段处理
- 获取jar中被指定注解标记的filed对象
- …
- 资源处理
- 获取jar中resource中的properties文件
- …
- 工具类:
- 过滤类中方法(类似stream流式写法)
- …
- 序列化为xml/json
- 更多能力见官方文档:https://github.com/ronmamo/reflections
三、使用demo
1 |
|
- 通过reflections.classes() 获取所有的class文件
- reflections需要传入configuration才能进行初始化
- configuration配置
- classloader:声明要扫描哪一个classloader下的class
- scanner:声明需要扫描哪些内容:type和annotation的scanner
- url:真实要扫描的jar执行流程
- 初始化configuration并设置
- classloader:声明要扫描哪一个classloader下的class
- scanner:声明需要扫描哪些内容:type和annotation的scanner
- url:真实要扫描的jar
四、主要流程源码分析
初始化, 调用
new Reflections(config)
执行如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public Reflections(final Configuration configuration) {
// 设置configuration
this.configuration = configuration;
// 设置存在class元信息的store对象,其内部维护 Map<String, Multimap<String, String>> storeMap
store = new Store(configuration);
if (configuration.getScanners() != null && !configuration.getScanners().isEmpty()) {
//inject to scanners
for (Scanner scanner : configuration.getScanners()) {
scanner.setConfiguration(configuration);
scanner.setStore(store.getOrCreate(scanner.getClass().getSimpleName()));
}
// 扫描configuration中持有的所有url
scan();
}
}扫描url, 调用
scan()
执行如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44protected void scan() {
// 一些代码...
// 遍历configuration中的所有url
for (final URL url : configuration.getUrls()) {
try {
// 如果configuration配置了线程池,则把scan加入到线程池异步执行
if (executorService != null) {
futures.add(executorService.submit(new Runnable() {
public void run() {
if (log != null && log.isDebugEnabled()) log.debug("[" + Thread.currentThread().toString() + "] scanning " + url);
scan(url);
}
}));
} else {
scan(url);
}
scannedUrls++;
} catch (ReflectionsException e) {
if (log != null && log.isWarnEnabled()) log.warn("could not create Vfs.Dir from url. ignoring the exception and continuing", e);
}
}
// 一些代码...
}
public void scan(URL url) {
// 通过迭代器遍历url中的所有符合要求的文件
for (final Vfs.File file : Vfs.fromURL(url).getFiles()) {
String input = file.getRelativePath().replace('/', '.');
if (configuration.getInputsFilter() == null || configuration.getInputsFilter().apply(input)) {
Object classObject = null;
// 遍历configuration中的声明的scanner实现类,扫描不同的内容并加入store
for (Scanner scanner : configuration.getScanners()) {
try {
if (scanner.acceptsInput(input)) {
classObject = scanner.scan(file, classObject);
}
} catch (Exception e) {
}
}
}
}存储, 根据传入的scanner的不同,执行不同的scan扫描逻辑,这里以
new TypeAnnotationsScanner()
为例1
2
3
4
5
6
7
8
9
10
11
12
13public void scan(final Object cls) {
// 获取class name
final String className = getMetadataAdapter().getClassName(cls);
for (String annotationType : (List<String>) getMetadataAdapter().getClassAnnotationNames(cls)) {
if (acceptResult(annotationType) ||
annotationType.equals(Inherited.class.getName())) { //as an exception, accept Inherited as well
// 以(注解,class name)为键值对,存入private Multimap<String, String> store;
getStore().put(annotationType, className);
}
}
}获取class对象, 通过注解去store中获取类集合
1
2
3
4
5
6public Set<Class<?>> getTypesAnnotatedWith(final Class<? extends Annotation> annotation, boolean honorInherited) {
// 直接去store中根据注解name去获取对应的class列表
Iterable<String> annotated = store.get(index(TypeAnnotationsScanner.class), annotation.getName());
Iterable<String> classes = getAllAnnotated(annotated, annotation.isAnnotationPresent(Inherited.class), honorInherited);
return Sets.newHashSet(concat(forNames(annotated, loaders()), forNames(classes, loaders())));
}
总结
reflections需要传入configuration才能进行初始化
configuration配置
- classloader:声明要扫描哪一个classloader下的class
- scanner:声明需要扫描哪些内容:type和annotation的scanner
- url:真实要扫描的jar
执行流程
初始化configuration并设置
classloader:声明要扫描哪一个classloader下的class
scanner:声明需要扫描哪些内容:type和annotation的scanner
url:真实要扫描的jar
执行scan,扫描指定url
根据设置的scanner,把对应的信息存入store
根据key去store获取指定信息
reflections使用总结
http://coder-xieshijie.cn/2022/11/13/java/reflections使用总结/