SpringBoot版本升级引起的FileNotFoundException——WebMvcConfigurerAdapter.class

缘起

最近公司项目要求JDK从8升到17,SpringBoot版本从2.x升级到3.x,期间遇到了一个诡异的FileNotFoundException异常,日志如下(敏感信息使用xxx脱敏)

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.xxx.xxx.OperationAnalysisApplication]
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:179)
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:397)
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:283)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:344)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:115)
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:745)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:565)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291)
	at com.xxx.xxx.OperationAnalysisApplication.main(OperationAnalysisApplication.java:34)
Caused by: java.io.FileNotFoundException: class path resource [org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.class] cannot be opened because it does not exist
	at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:211)
	at org.springframework.core.type.classreading.SimpleMetadataReader.getClassReader(SimpleMetadataReader.java:54)
	at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:48)
	at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:103)
	at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.createMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:86)
	at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.getMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:73)
	at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:81)
	at org.springframework.context.annotation.ConfigurationClassParser.asSourceClass(ConfigurationClassParser.java:611)
	at org.springframework.context.annotation.ConfigurationClassParser$SourceClass.getSuperClass(ConfigurationClassParser.java:924)
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:335)
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:244)
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:189)
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:298)
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:244)
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:197)
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:165)
	... 13 common frames omitted

SpringBoot3.x已经删除了类WebMvcConfigurerAdapter,建议实现接口WebMvcConfigurer

过程

1. 查找当前项目中使用WebMvcConfigurerAdapter的地方

这个报错日志明显没有提示出哪个类有问题,先排除当前项目自己写的代码有没有这个类,于是在IDEA中使用全局查找来查找使用WebMvcConfigurerAdapter的地方,发现都被WebMvcConfigurer接口替代了,看来并不是自己写的代码里面的,二是某个Jar中的,这大概就是没有显示因为哪个类继承了WebMvcConfigurerAdapter导致异常的原因吧

2. 查找哪个Jar中引用了这个类

下个断点看看

这TM和大海捞针没区别啊,这项目光依赖自己的包就几十个,大部分都是公司内部包,我都没有源码,这可怎么找啊,只能去报异常的地方碰碰运气了。我找到了报异常的地方:
日志显示在这

at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:211)

源码如下:

public InputStream getInputStream() throws IOException {
   InputStream is;
    if (this.clazz != null) {
        is = this.clazz.getResourceAsStream(this.path);
    } else if (this.classLoader != null) {
        is = this.classLoader.getResourceAsStream(this.absolutePath);
    } else {
        is = ClassLoader.getSystemResourceAsStream(this.absolutePath);
    }

    if (is == null) {
        throw new FileNotFoundException(this.getDescription() + " cannot be opened because it does not exist");
    } else {
        return is;
    }
}

报异常的地方很明显了,就是这

 if (is == null) {
     throw new FileNotFoundException(this.getDescription() + " cannot be opened because it does not exist");
 }

在这里下断点,启动项目,发现这个类里this.clazz是null,this.classLoader不是null,感觉这个classloader应该就是加载某个类的时候发现它的父类是WebMvcConfigurerAdapter,去加载WebMvcConfigurerAdapter找不到才报错的。就去这个classloader里面翻找了一下,感觉最有价值的就是里面的classes属性了,如下:
在这里插入图片描述

当前实例中的classes中找找

里面居然已经加载了5285个类,一个一个的看显然不行,于是在classes上右键,然后选择评估表达式,想着这个classes是个ArrayList,使用classes.stream().filter()筛选一下加载的类里面是否有父类是WebMvcConfigurerAdapter的,找到了不久知道是哪个有问题了么。写好筛选条件后执行,报错如下:
在这里插入图片描述
这…大概是JDK里面很多类还没加载导致的吧,看来这条行不通了。于是考虑这个classesArrayList类型,有序列表啊,其中最后一个元素有没有可能是当前继承了WebMvcConfigurerAdapter的类么?于是使用评估表达式获取了最后一个元素,很遗憾,是个idea的类:
在这里插入图片描述
梦想再一次破灭了。

是不是当前类加载器能提供点什么信息

想着是不是当前类加载器能看到当前在加载哪个类或者哪个类的加载引起了当前类的加载啊?很遗憾,classloader根本没有这信息,只有当前类加载器正在加载的这个类WebMvcConfigurerAdapter

看看谁触发了当前类加载

很遗憾,上面的方法都没找到很有用的信息,于是想着,看看谁调用了当前方法,也就是说谁触发了加载WebMvcConfigurerAdapter这个类的动作,于是顺着调用栈:
在这里插入图片描述
一直往回找,终于,在下面这个地方找到了:
在这里插入图片描述
这里点开resource字段,直接定位到类:

import com.zhongan.data.analytics.interceptor.RequestDataInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
    public InterceptorConfig() {
    }

    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestDataInterceptor()).addPathPatterns(new String[]{"/**"});
        super.addInterceptors(registry);
    }
}

就是这了。
Jar里面没法排掉某个特定的类,只能在当前项目中创建一个和这个类一模一样的类,代码改成自己想要的。因为Java中,某个类(同一个classloader+全限定名)已经被加载了,就不会再次被加载,项目中的类加载优先于Jar包中的,又都是同一个类加载器加载,所以会优先加载到项目中类,Jar中的则不会被加载了,曲线救国 我试了下似乎不行,待考证,暂时先加删除线,后续会回来看看怎么解决这个问题。
-------------------------------------------------------->分割线20230729<------------------------------------------------------------------------------
最后在项目里创建了一个package :org.springframework.web.servlet.config.annotation然后把WebMvcConfigurerAdapter拷贝进来,把InterceptorConfig 在SpringBoot启动类上设置为不扫描,把问题解决了。不创建包org.springframework.web.servlet.config.annotation并拷贝WebMvcConfigurerAdapter直接在SpringBoot启动类上设置为不扫描是不行的,因为你设置InterceptorConfig 不扫描JVM会加载这个类,这个类有父类就先尝试加载父类WebMvcConfigurerAdapter,父类不存在,直接报错。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/49297.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Gitlab 合并分支与请求合并

合并分支 方式一&#xff1a;图形界面 使用 GitGUI&#xff0c;右键菜单“GitExt Browse” - 菜单“命令” - 合并分支 方式二&#xff1a;命令行 在项目根目录下打开控制台&#xff0c;注意是本地 dev 与远程 master 的合并 // 1.查看本地分支&#xff0c;确认当前分支是否…

【ARM Coresight 系列文章 10.3 - ARM Coresight STM 寄存器介绍 及STM DMA 传输介绍】

文章目录 STM Register summarySTM DMA 相关的寄存器DMA TransferBurst requestSingle and burst request STM Register summary STM 的寄存器主要可以分为以下几类&#xff1a; STM DMA 相关的&#xff1b;STM HW Trigger 相关的&#xff1b;系统控制及状态寄存器&#xff1…

25.6 matlab里面的10中优化方法介绍——模拟退火算法(matlab程序)

1.简述 相信没有相关物理知识背景的小伙伴看到“退火”二字是一脸懵逼的...固体的退火过程指的是将固体加热至足够高的温度&#xff0c;再使其慢慢冷却的过程。在加热过程中&#xff0c;原本有序排列的内部粒子开始无序运动&#xff0c;此时固体的内能不断增大&#xff1b;而在…

Nginx 高可用负载均衡(三种模式)

一、nginx普通集群负载均衡 1、安装keepalived (1)下载 https://www.keepalived.org/download.html(2)解压 tar -zxvf keepalived-2.0.18.tar.gz(3)使用configure命令配置安装目录与核心配置文件所在位置&#xff1a; ./configure --prefix/usr/local/keepalived --sysconf/e…

Vlan端口隔离(第二十四课)

一、端口隔离 1、端口隔离技术概述 1)端口隔离技术出现背景:为了实现报文之间的二层隔离,可以将不同的端口加入不同的VLAN,但这样会浪费有限的VLAN ID资源。 2)端口隔离的作用:采用端口隔离功能,可以实现同一VLAN内端口之间的隔离。 3)如何实现端口隔离功能:只需要…

十五章:使用类别峰值响应的弱监督实例分割

0.摘要 目前&#xff0c;使用图像级别标签而不是昂贵的像素级掩码进行弱监督实例分割的研究还未得到充分探索。本文通过利用类别峰值响应来实现一个分类网络&#xff0c;用于提取实例掩码&#xff0c;来解决这个具有挑战性的问题。只通过图像标签的监督下&#xff0c;完全卷积的…

HBuilder 编辑器终端窗口无法输入,未响应的解决方案

HBuilder 编辑器终端窗口无法输入&#xff0c;未响应的解决方案 一、找到 HBuilder 安装目录 找到 main.js HBuilderX - plugins - builtincef3terminal - script - main.js 二、编辑 main.js 将 main.js 文件中的 powershell.exe 和 cmd.exe 路径都改为绝对路径 C:/Windows…

【深度学习】WaveMix: A Resource-efficient Neural Network for Image Analysis 论文

论文&#xff1a;https://arxiv.org/abs/2205.14375 代码&#xff1a;https://github.com/pranavphoenix/WaveMix 文章目录 ABSTRACTIntroductionBackground and Related WorksWaveMix Architectural FrameworkOverall architectureWaveMix block Experiments and ResultsTasks…

activemq消息中间件

ActiveMQ消息中间件详解 下载地址&#xff1a;https://activemq.apache.org/activemq-5015009-release 1、MQ的产品种类 1.1、消息中间件的特性/共同特性/共同维度 Kafka&#xff08;大数据专用、由java/scala编写&#xff09; API发送和接收MQ的高可用性MQ的集群和容错配置…

Docker 之 Consul容器服务更新与发现

一、Consul介绍 1、什么是服务注册与发现 服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的&#xff0c;不保障高可用性&#xff0c;也不考虑服务的压力承载&#xff0c;服务之间调用单纯的通过接口访问。直到后来出现了多个节点的分布式架构&#xff…

Android平台GB28181设备接入侧如何同时对外输出RTSP流?

技术背景 GB28181的应用场景非常广泛&#xff0c;如公共安全、交通管理、企业安全、教育、医疗等众多领域&#xff0c;细分场景可用于如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终…

Flutter的开发环境搭建-图解

前言&#xff1a;Flutter作为一个移动应用开发框架&#xff0c;具有许多优点和一些局限性。最大的优点就是-跨平台开发&#xff1a;Flutter可以在iOS和Android等多个平台上进行跨平台开发&#xff0c;使用一套代码编写应用程序&#xff0c;节省开发时间和成本。 Flutter可以编…

了解Unity编辑器之组件篇Mesh(三)

Mesh&#xff1a;是一种三维模型的表示形式&#xff0c;它由一系列顶点、三角形&#xff08;或其他多边形&#xff09;和相关属性组成。Mesh用于表示物体的外观和形状&#xff0c;它是可见物体的基本组成部分。通过操作Mesh&#xff0c;开发者可以实现各种视觉效果、物理模拟和…

基于PCA和小波算法联合实现红外与可见光图像融合的Matlab仿真(完整源码+35组数据集)

以下是一个使用PCA和小波实现红外与可见光图像融合的Matlab仿真完整源码。源码中只需修改红外图像&#xff08;IR.bmp&#xff09;和可见光图像&#xff08;VI.bmp&#xff09;名字即可 文章目录 效果展示数据集展示步骤说明完整源码下载地址 效果展示 最终融合效果展示&#x…

java执行ffmpeg命名的Docker镜像制作

今天来记录一下通过Dockerfile制作docker镜像的过程 背景 我需要通过java服务调用ffmpeg去执行视频合并的功能&#xff0c;想把这个环境封装到docker镜像当中&#xff0c;方便以后迁移部署。 实现方法 随便找一个路径创建一个Dockerfile文件 touch Dockerfilevim Dockerfi…

如何使用vscode连接远程服务器

1、安装remote-ssh 在应用商店搜索remote-ssh&#xff0c;安装remote-ssh 2、安装完成后会出现远程资源管理器 3、点击远程资源管理器 --ssh的➕号&#xff0c;在输出框内输入要连接的服务器ip及账户名 如&#xff1a;ssh 账户名ip地址 4、输入后回车保存 5、保存后刷新一下 6…

Redis学习路线(1)—— Redis的安装

一、NoSQL SQL VS NoSQL 1、名称 SQL 主要是指关系数据库。NoSQL 主要是指非关系数据库。 2、存储结构 SQL 是结构化的数据库&#xff0c;以表格的形式存储数据。NoSQL 是非结构化的数据库&#xff0c;以Key-Value&#xff08;Redis&#xff09;&#xff0c;JSON格式文档&…

【React】版本正确安装echarts-liquidfill(水球图表)包引入不成功问题

目标效果图&#xff1a; 安装&#xff1a; npm install echarts npm install echarts-liquidfill 引入&#xff1a; Import:import * as echarts from echarts; import echarts-liquidfill 或 import echarts-liquidfill/src/liquidFill.jsOr:import * as echarts from…

TreeMap的底层实现

0. 你需要知道的TreeMap的内置属性 0.1 节点属性 K key; // 键 V value; // 值 Entry<K,V> left; // 左子节点 Entry<K,V> right; // 右子节点 Entry<K,V> parent; // 父节点 boolean color; // 节点的颜色0.2 成员变量 //比较器对象private f…

Android性能优化之游戏引擎初始化ANR

近期&#xff0c;着手对bugly上的anr 处理&#xff0c;记录下优化的方向。 借用网上的一张图&#xff1a; 这里的anr 问题是属于主线程的call 耗时操作。需要使用trace 来获取发生anr前一些列的耗时方法调用时间&#xff0c;再次梳理业务&#xff0c;才可能解决。 问题1 ja…