一个传递依赖导致的应用崩溃

本文分析了一次因Jackson版本不兼容导致Spring Boot应用启动失败的案例,详细讲述了如何定位问题,以及解决由版本差异引发的NoSuchMethodError错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 问题

最近我们有个应用合并了一个任务的代码之后应用无法启动,报下面的错误:

Caused by: java.lang.NoSuchMethodError: org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.modulesToInstall([Lcom/fasterxml/jackson/databind/Module;)Lorg/springframework/http/converter/json/Jackson2ObjectMapperBuilder;
at org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration.configureModules(JacksonAutoConfiguration.java:259)
at org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration.jacksonObjectMapperBuilder(JacksonAutoConfiguration.java:186)
at org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration$EnhancerBySpringCGLIB$82b81f51.CGLIB$jacksonObjectMapperBuilder$1(<generated>)
at org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration$$EnhancerBySpringCGLIB$$82b81f51$$FastClassBySpringCGLIB$$ce0faa75.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:309)
at org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration$$EnhancerBySpringCGLIB$$82b81f51.jacksonObjectMapperBuilder(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 16 more

从日志里面可以很明显的看出来框架里面调用的org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.modulesToInstal这个方法不存在,参数类型不对,调用传入的是数组类型,但是jar里面的方法定义是Class类型的。以前也遇到过类似的问题一般是Spring版本差异导致的,应用依赖的spring-web 4.1.4,这个版本确实不存在上面的那个方法,但是查看4.1.7的版本发现这个方法是存在的,讲道理应该是直接升级spring-web版本的,但是查看线上依赖的也是这个版本而且一直正常运行,而直接修改spring版本号有无法预估的风险,需要时间充分测试才能上线,为了降低风险还是从最近的任务入手,看是最近哪些任务修改导致了这次错误。
由于线上代码是正常运行的,所以为了比较差异最快的办法是把线上应用依赖的jar和当前测试环境依赖的jar包都拉出来进行对比。比较发现当前测试版本多依赖了下面几个可疑的jar包:

spring-boot-starter-web-1.1.10.RELEASE.jar
spring-boot-starter-tomcat-1.1.10.RELEASE.jar
jackson-core-2.3.4.jar
jackson-databind-2.3.4.jar
jackson-module-jaxb-annotations-2.3.3.jar

看代码提交记录这几个变化都是由于新任务引入了一个oms-service-api包间接引入的。看到上面的差异马上就把目光锁定在spring-boot-starter-web和spring-boot-starter-tomcat这两个,因为应用使用了spring boot框架并开启了AutoConfiguration特性,所以怀疑是这两个jar额外触发了一系列bean的加载导致进入了之前没进入过的框架逻辑导致的,马上exclude掉这两个依赖重新启动,但是应用还是无法启动,还是一样的错误。没办法只能挨个试,最后发现把jackson-databind这个依赖exclude掉之后,应用就正常启动了。。。

  • 原因分析

为啥classpath下多了这个jar包就会导致spring-boot中的错误呢?查看一下org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration这个内部类的代码:
在这里插入图片描述

在这里插入图片描述
这个内部类定义了一个ConditionalOnClass注解。spring在加载bean配置时,会调用spring-context的Condition框架对所有带Conditional注解的bean进行条件判断是否需要跳过bean配置的加载。定义了ConditionalOnClass注解的bean配置在加载该bean时会检查value中的Class是否存在于应用的classpath中,只有存在时才加载,否则直接跳过,可以查看org.springframework.boot.autoconfigure.condition.OnClassCondition中的源码。而ObjectMapper这个类刚好是jackson-bind这个jar包中的,所以classpath新加了jackson-bind包之后,org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration这个bean配置的加载就不会跳过了,容器就会初始化Jackson2ObjectMapperBuilder这个bean,然后就会走到configureModules这个有问题的方法。从这也可以看出来,jackson-bind其实是背锅的,应用中本来就一直存在隐患,只是之前没有暴露,而它让错误暴露了,根本原因还是应用中依赖了spring不兼容的版本,终极解决方案还是要把spring-web版本号升到4.1.7。

  • 结语

maven虽好,它强大的依赖管理能替我们开发省不少事,但是在开发中在增加了任何新依赖时都要谨慎对待它带来的间接依赖有没有副作用,有时候一个小小的版本号变化会直接导致应用崩溃,最近已经遇到过多起传递依赖导致的问题了。在对外开放api时最好关掉传递依赖,比如把optional设置成true或者把scope设置成provide,特别是spring这种关键的依赖,可能会直接把依赖方搞崩。

### 可能的原因分析 QT 应用程序在同一环境中因 `libc.so` 导致崩溃的问题可能涉及多个方面。以下是几个常见的原因: 1. **动态链接库版本不一致** 如果目标机器上的 `glibc` 版本低于编译时使用的版本,则可能会导致兼容性问题。这是因为较新的 glibc 功能无法在旧版上正常工作[^1]。 2. **编译选项不当** 编译 QT 应用程序时未指定合适的架构或浮点运算支持可能导致运行时错误。例如,在嵌入式设备中,如果缺少 `-msoft-float -D__GCC_FLOAT_NOT_NEEDED` 这样的编译标志,可能会引发“非法指令”等问题[^2]。 3. **内存分配冲突** 若存在 DDR 和 FLASH 的分区设置不合理或者有重叠区域,也可能影响到系统的稳定性,进而造成应用程序崩溃[^3]。 4. **初始化过程中的依赖缺失** Linux 内核的 `init` 文件夹负责启动阶段的关键操作。如果核心组件如 `main.c` 配置失误,可能间接影响用户空间的应用行为,包括 QT 程序的行为[^4]。 --- ### 解决方案建议 #### 方法一:确认并统一 glibc 版本 确保开发主机与目标平台之间的 GNU C Library (glibc) 版本匹配非常重要。可以通过以下命令检查当前系统所安装的 glibc 版本: ```bash ldd --version ``` 对于跨平台部署场景,推荐采用交叉编译工具链来构建适合特定硬件环境下的二进制文件,并明确指定目标平台对应的 libc 路径。 #### 方法二:调整 GCC 编译参数 针对 ARM 或其他低功耗处理器架构,适当增加软浮动点计算相关的标记可以有效规避潜在的风险。具体做法是在 Makefile 中加入如下定义: ```makefile CFLAGS += -msoft-float -D__GCC_FLOAT_NOT_NEEDED ``` 此外还可以尝试启用更多的调试信息以便于定位实际发生的位置: ```makefile CFLAGS += -O0 -ggdb ``` #### 方法三:优化存储布局规划 为了避免可能出现的数据覆盖现象,合理安排各功能模块所需的地址区间至关重要。比如将常驻型数据放置于 ROM 区域而非常规 RAM 地址范围内;同时也要留意是否存在越界访问等情况的发生。 #### 方法四:验证内核配置项准确性 重新审视一下 .config 文件里关于进程调度策略、信号机制等方面的选择是否恰当。有时候即使看似无关紧要的小改动也会影响到最终效果表现出来。特别是涉及到多线程并发控制的部分更需谨慎对待。 最后别忘了执行完整的 make clean 命令后再继续后续流程以免残留物干扰新生成的结果质量。 --- ### 总结 综上所述,解决 QT 应用由于 `libc.so` 引发崩溃的情况可以从四个方面入手:一是核查双方共享的标准函数库等级差异情况;二是改善编译期间传递进去的各项属性设定值;三是精心设计物理媒介间相互作用关系图谱防止意外碰撞事件产生;四是仔细审查操作系统底层框架搭建细节寻找隐藏漏洞所在之处加以修正完善整个体系结构从而达到预期目的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值