一、项目背景
背景:项目中有解析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
public Set<Class<?>> queryClass(String jarPath, String url) throws MalformedURLException {
// 根据jarPath去构建classloader,此处是自定义classloader
WarClassLoader warClassLoader =
SwaggerGenerator.getWarClassLoader(jarPath, Thread.currentThread().getContextClassLoader());
// 构建configuration,设置classloader和要解析的url
ConfigurationBuilder config = ConfigurationBuilder.build();
config.addClassLoader((URLClassLoader) warClassLoader.getParent());
config.setScanners(new ResourcesScanner(), new TypeAnnotationsScanner(), new SubTypesScanner());
config.getUrls().clear();
config.getUrls().add(new URL(url)); // 需要解析哪一个jar就传入对应的url地址
// 构建Reflection对象,获取符合指定注解的class
Reflections ref = new Reflections(config);
Stream<Class<?>> apiStream = ref.getTypesAnnotatedWith(Api.class).stream();
Stream<Class<?>> restStream = ref.getTypesAnnotatedWith(RestController.class).stream();
Stream<Class<?>> apiAndDef = Stream.concat(apiStream, restStream);
// 反击class的set集合
return apiAndDef.collect(Collectors.toSet());
}
- 通过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)执行如下public 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()执行如下protected 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()为例public 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中获取类集合
public 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获取指定信息