Reflections扫描不到Class和Method对象

news/2024/5/19 4:01:04 标签: java, 反射, Reflections

问题

最近在SpringBoot 2.x项目中使用Reflections工具的时候(Jar包的版本是org.reflections:reflections:0.10.2),发现在IntelliJ IDEA中运行是能正常扫描出Class对象,但是部署在测试环境或者本地以Jar报运行时,扫描不出来,所以Debug了Reflections源码。

原因

因为我创建Reflections对象写法是这样的

java">Reflections reflections = new Reflections("com.jay.userinterface", Scanners.MethodsAnnotated);

点进去最终会调用这个方法来初始化配置

java">public static ConfigurationBuilder build(Object... params) {
        final ConfigurationBuilder builder = new ConfigurationBuilder();

        // flatten
        List<Object> parameters = new ArrayList<>();
        for (Object param : params) {
            if (param.getClass().isArray()) { for (Object p : (Object[]) param) parameters.add(p); }
            else if (param instanceof Iterable) { for (Object p : (Iterable) param) parameters.add(p); }
            else parameters.add(param);
        }

        ClassLoader[] loaders = Stream.of(params).filter(p -> p instanceof ClassLoader).distinct().toArray(ClassLoader[]::new);
        if (loaders.length != 0) { builder.addClassLoaders(loaders); }

        FilterBuilder inputsFilter = new FilterBuilder();
        builder.filterInputsBy(inputsFilter);

        for (Object param : parameters) {
            if (param instanceof String && !((String) param).isEmpty()) {
                builder.forPackage((String) param, loaders);
                inputsFilter.includePackage((String) param);
            } else if (param instanceof Class && !Scanner.class.isAssignableFrom((Class) param)) {
                builder.addUrls(ClasspathHelper.forClass((Class) param, loaders));
                inputsFilter.includePackage(((Class) param).getPackage().getName());
            } else if (param instanceof URL) {
                builder.addUrls((URL) param);
            } else if (param instanceof Scanner) {
                builder.addScanners((Scanner) param);
            } else if (param instanceof Class && Scanner.class.isAssignableFrom((Class) param)) {
                try { builder.addScanners(((Class<Scanner>) param).getDeclaredConstructor().newInstance()); }
                catch (Exception e) { throw new RuntimeException(e); }
            } else if (param instanceof Predicate) {
                builder.filterInputsBy((Predicate<String>) param);
            } else throw new ReflectionsException("could not use param '" + param + "'");
        }

        if (builder.getUrls().isEmpty()) {
            // scan all classpath if no urls provided todo avoid
            builder.addUrls(ClasspathHelper.forClassLoader(loaders));
        }

        return builder;
    }

在For循环中第一个if,如果是String类型的参数,就会设置package,然后会设置filter,问题就出现在这里。这种简写方式,filter是和包名一样的。在本地IDEA中,所有文件都是在out目录下,文件的目录是正常包名开头,如下格式

java">com/jay/userinterface/authority/model/dto/ProductVO.class

但是如果是以Jar包运行的方式,因为SpringBoot 2.x版本打包时会做一些处理(加一些启动类),导致文件结构会发生变化(读者可以解压一个SpringBoot的Jar包看看实际结构)。这种情况下,获取文件的名称是如下格式

java">BOOT-INF/classes/com/jay/userinterface/authority/model/dto/ProductVO.class

在扫描过程中,这些文件都过不了Filter的校验。

大致过程就是在Reflections类中scan()方法,对每个文件都会根据Filter过滤下,这个Filter就是一个正则表达式的匹配,表达式就是com/jay/userinterface/*,以Jar包方式运行的话,所有文件都会被过滤掉,扫描结果就为空。

解决方案

使用另外一种写法,自己构造ReflectionsConfiguration,手动设置Filter

java">Reflections reflections = new Reflections(new ConfigurationBuilder()
                .forPackages(packageName)
                .filterInputsBy(new FilterBuilder().includePackage("BOOT-INF.classes." + packageName))
                .setScanners(Scanners.MethodsAnnotated));

我这里面是直接加了前缀,每个文件在Jar包中的实际路径,和Springboot打包后文件格式有关,Springboot 1.x版本应该是不用改的。

也可以通过FilterBuilderincludePattern()方法来直接写正则表达式,兼容IDEA运行和Jar包运行的方式。


http://www.niftyadmin.cn/n/173645.html

相关文章

如何在谷歌中优化外贸网站,提高业务利润?

随着全球贸易的不断发展&#xff0c;越来越多的企业开始通过外贸网站开展国际贸易。 而在这个过程中&#xff0c;如何让外贸网站在谷歌中排名更高&#xff0c;成为了一个关键的问题。 因为谷歌作为全球最大的搜索引擎&#xff0c;拥有着无数的潜在客户。 如果能够通过谷歌优…

一个输入框背景色改不了?去除浏览器自动填充的背景颜色

START 番茄又来写点啥啦&#xff0c;今天遇到一个有趣的事情&#xff0c;朋友找到我&#xff0c;说他改一个输入框的背景颜色&#xff0c;改了好久&#xff0c;叫我帮忙看看。我满脸问号&#xff1f;很难吗&#xff1f;当我了解到实际的需求&#xff0c;发现确实有点有趣&…

C++使用rapidjson进行类的序列化与反序列化

目录序列化&反序列化单个对象序列化反序列化使用示例序列化&反序列化对象列表C中可以使用第三方库来实现将类序列化成JSON文件&#xff0c;以及读取JSON文件内容反序列化为类对象。 这里使用rapidJson,github链接&#xff1a;https://github.com/Tencent/rapidjson 使用…

CRC校验算法以及相关实现示例

一、CRC校验算法介绍CRC&#xff08;Cyclic Redundancy Check&#xff09;校验算法是一种常用的数据传输错误检测算法&#xff0c;它通过对数据进行一个除余运算得到校验码。在发送数据时&#xff0c;发送方先计算出校验码&#xff0c;并将校验码随数据一起发送给接收方&#x…

Spark常用代码

Spark常用代码 文章目录Spark常用代码1. 创建RDD方法2. 专门读取小文件wholeTextFiles3. rdd的分区数4. Transformation函数以及Action函数4.1 Transformation函数4.2 Action函数4.3 其他常见的函数5. 重分区函数6. 聚合函数6.1 基础聚合函数6.2 Key-Value类型的聚合函数6.3 jo…

win下pytorch安装—cuda11.7 + cudnn8.4 + pytorch1.13安装

安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch安装一、cuda安装 下载地址&#xff1a;cuda下载官网链接 1.1、cuda版本选择 这里有个前置工作需要搞清楚的&#xff0c;就是自己的显卡支持的cuda版本。 点击电脑左下角开始菜单找到 点击【帮…

Python嵌套函数(Nested function)和闭包(closure)

Python嵌套函数&#xff08;Nested function&#xff09;和闭包&#xff08;closure&#xff09; 闭包&#xff08;closure&#xff09;是建立在嵌套函数基础上的&#xff0c;是一种特殊的嵌套函数结构。 先看嵌套函数&#xff08;Nested function&#xff09;。 Python允许…

2023深度解析数据治理平台建设

前言 阿里巴巴一直将数据作为自己的核心资产与能力之一&#xff0c;通过多年的实践探索建设数据应用&#xff0c;支撑业务发展。在不断升级和重构的过程中&#xff0c;我们经历了从分散的数据分析到平台化能力整合&#xff0c;再到全局数据智能化的时代。如今&#xff0c;大数…