当前位置: 首页 > 工具软件 > Reflections > 使用案例 >

Reflections反射扫描库

谭卜鹰
2023-12-01

1. 使用场景

Reflections扫描classpath, 缓存metadata, 以备运行期间使用.

  • 可获取某类的所有子类
  • 可获取某注解标注的所有类或字段
  • 可获取某正则匹配的资源
  • 可获取特定签名的方法
  1. 优点

    具备Java原生反射技术, 所不具有的功能, 反射扫描.

  2. 缺点

    底层实现, 会遍历classpath, 以及遍历jar包中的类, 太耗时间.

    只能在启动时, 做些初始化的功能.

2. 简单使用

  1. 模型

    package demo.java.reflections.model;
    
    import java.io.Serializable;
    
    public class BaseModel implements Serializable {
    }
    
    public class Account extends BaseModel {
    }
    
    public class User extends BaseModel {
    }
    
  2. 测试 (Java Main)

    package demo.java.reflections;
    
    import demo.java.reflections.model.BaseModel;
    import org.reflections.Reflections;
    import org.reflections.scanners.SubTypesScanner;
    import org.reflections.util.ClasspathHelper;
    import org.reflections.util.ConfigurationBuilder;
    import org.reflections.util.FilterBuilder;
    
    public class ReflectionsTest {
    
        /**
         * 如下示例
         * 1. 基本使用 和 高级使用 的方式是等价的
         * 2. 运行耗时主要在new Reflections()
         * 3. Reflections(Scanner:扫描器, URL:扫描路径), 扫描器和扫码路径 越少越好, 这个非常影响耗时!!!
         * 4. 这种反射扫描框架, 还是少用为好. 可以考虑用 "Spring IOC", "Java SPI", "配置文件解析" 等方式解决.
         * @param args
         */
        public static void main(String[] args) {
            // 基本使用
            Reflections reflections1 = new Reflections("demo.java.reflections.model");
            System.out.println(reflections1.getSubTypesOf(BaseModel.class));
    
            // 高级使用
            Reflections reflections2 = new Reflections(new ConfigurationBuilder()
                    .setUrls(ClasspathHelper.forPackage("demo.java.reflections.model"))
                    .setScanners(new SubTypesScanner())
                    .filterInputsBy(new FilterBuilder().includePackage("demo.java.reflections.model"))
            );
            System.out.println(reflections2.getSubTypesOf(BaseModel.class));
        }
    }
    
    
    1. 测试 (SpringBoot Main)
    package demo.java.reflections;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class ReflectionsApp {
        public static void main(String[] args) {
            SpringApplication.run(ReflectionsApp.class, args);
    
            ReflectionsTest.main(args);
        }
    }
    

3. 常见错误

  1. 错误 (zip file closed)
  • 问题现象
    idea跑java main方法正常, idea跑springboot main方法正常. cmd跑springboot fat-jar, 报如下异常

  • 解决方案

    ​ 目前: 把reflections从0.9.12降到0.9.11. 详细参考issues

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.reflections.ReflectionsException: Scanner SubTypesScanner was not configured
        at org.reflections.Store.get(Store.java:39)
        at org.reflections.Store.get(Store.java:61)
        at org.reflections.Store.get(Store.java:46)
        at org.reflections.Store.getAll(Store.java:93)
        at org.reflections.Reflections.getSubTypesOf(Reflections.java:404)
        at demo.java.reflections.ReflectionsTest.main(ReflectionsTest.java:32)
        at demo.java.reflections.ReflectionsApp.main(ReflectionsApp.java:11)
        ... 8 more
  1. 错误 (尝试获取所有java.lang.Number的子类, 失败)

    • 问题现象

      idea跑java main方法正常, idea跑springboot main方法正常. cmd跑springboot fat-jar异常

    • 问题原因

      idea跑项目时, 会带上classpath, 这方便reflections从jar包中查找java.lang.Number的子类

      另, springboot入口org.springframework.boot.loader.JarLauncher#main

      有自定义的ClassLoader(LaunchedURLClassLoader)

4. 参考

  1. reflections

  2. reflections-issues | java.lang.IllegalStateException: zip file closed

  3. reflections-issues | spring boot use happen error

  4. Is it possible to get all the subclasses of a class? [duplicate]

 类似资料: