一次 Spring 无法启动的问题排查(字节码篇)

java 疑难杂症(一)springboot 项目启动不起来又没有报错 一 问题 新建了一个sprintboot 项目,启动时启动不起来,刚启动就关闭,还没有报错信息,启动类利用 try catch 也捕获不到异常,启动后现象如下: 二 解决办法 查看了网上的解决办法,没有效果,但是大体思路都是认为依赖冲突导致的,所以查看 pom 文件,试了多次终于成功,发现是 web 包和 tomcat 包同时存在引起的,所以把 tomcat 依赖注释掉就好用了。 原 pom 文件依赖是: <dependencies> <dependency> <g 阅读详情

问题背景

有同学反馈,有一个项目从 kotlin 1.2 升级到 kotlin 1.3 以后 Spring 项目无法启动,报
java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'xxx' method 错误

没有引入任何其它变量,只是更改了 kotlin 的版本,猜测可能是编译出来的字节码不一样,出问题的函数如下。

@OptionalAuthAPI
@GetMapping("/page")
fun getActivityGameModulePage(
        @OptionalAuthRes authRes: OptionalAuthResDTO,
        @RequestParam(name = "type", defaultValue = "0") type: Int = 0,
        @RequestParam(name = "page", defaultValue = "0") page: Int = 0,
        @RequestParam(name = "pageSize", defaultValue = "30") pageSize: Int = 0
): APIResult<Page<ActivityGameModuleRespDTO>> {
    return;
}

kotlin 处理函数中 default 值的方法是生成一个静态的函数,比如下面的函数。

class MyTest1 {
    private var m = 101

    fun foo(x: Int = 100, y: String = "foo", z: Double = 1.0) {
        println("" + x + y + m + z)
    }

    fun bar() {
        foo(101, "bar")
        foo(101);
        foo();
    }
}

生成的部分字节码如下,主要看函数签名

  public final void foo(int, java.lang.String, double);
    descriptor: (ILjava/lang/String;D)V
    flags: ACC_PUBLIC, ACC_FINAL

  public static void foo$default(MyTest1, int, java.lang.String, double, int, java.lang.Object);
    descriptor: (LMyTest1;ILjava/lang/String;DILjava/lang/Object;)V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC

通过阅读字节码,人肉翻译为 java 就是:

public class MyTest3 {
    private int m;

    public void foo(int x, String y, double z) {
        String str = "" + x + y + this.m + z;
        System.out.println(str);
    }

    public void bar() {
        foo$default(this, 101, "bar", 0.0D, 4, null); // 4 = b0100
        foo$default(this, 101, null, 0.0D, 6, null); // 6 = b0110
        foo$default(this, 0, null, 0.0D, 7, null); // 7 = b0111
    }

    public static void foo$default(MyTest3 thisObj, int x, String y, double z, int mask, Object obj) {
        if ((mask & 0x01) != 0) {
            x = 100;
        }
        if ((mask & 0x02) != 0) {
            y = "foo";
        }
        if ((mask & 0x04) != 0) {
            z = 1.0;
        }
        thisObj.foo(x, y, z);
    }
}

由此可以看到 kotlin 对于默认参数的处理办法就是用一个 mask,告诉后面的逻辑,特定位置的参数是否需要使用默认值。

回到原 getActivityGameModulePage 方法,这个方法上有两个注解,kotlin 在编译以后会新增一个 static 的方法

// 默认方法
@OptionalAuthAPI
@GetMapping("/page")
public static 
APIResult<Page<ActivityGameModuleRespDTO>> 
getActivityGameByPage(...) {
}

// 新增方法
@OptionalAuthAPI
@GetMapping("/page")
public static 
APIResult<Page<ActivityGameModuleRespDTO>> 
getActivityGameByPage$default(...) {
}

咦,这样 Spring 在扫描的时候,不会出问题吗?两个方法都标注了 @GetMapping("/page") 要处理,理论上不论是 Koltin1.2 还是 1.3 在处理的时候都会出问题才对。

遇事不决,上字节码

kotlin 1.2 编译出来的字节码

public static APIResult getActivityGameByPage$default();
   flags: ACC_PUBLIC, ACC_STATIC, ACC_BRIDGE, ACC_SYNTHETIC

kotlin 1.3 编译出来的字节码

public static APIResult getActivityGameByPage$default();
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC

经过仔细对比,发现只有该方法的 flags 上面有一些区别,1.3 的字节码少了 ACC_BRIDGE 。

众所周知知, ACC_BRIDGE 是一种为了实现某些语言特性而由编译器自动生成的方法。除了 Kotlin,Java 自己本身在实现类型擦除等场景下也会用到 ACC_BRIDGE ,具体我这里就不展开了,大家可以去试一下。

是不是就是这个导致的问题呢?

我们来看我们当前用的什么 Spring 版本是如何处理方法的,通过调试我们进入到了这个方法

可以看到 Spring 4.3.10 版本判断是否是用户自己写的方法时的逻辑是方法不是 bridge 且方法不同于 Object 类中,因此现在情况就很明朗了。

在 kotlin1.2 中文,因为编译出的 getActivityGameByPage$default() 包含了 bridge,在 Spring 扫描的过程中就会被忽略掉,而 kotlin1.3 中,因为方法签名不包含 bridge,所以被当做了用户自己书写的方法,参与到扫描中,这样 controller 就冲突了,所以报了 Ambiguous mapping 错误。

如何解决

那这么严重的问题,难道 kotlin 不解决吗?是的,kotlin 不解决,那就只能上层框架兼容了,Spring 在后续的版本中做了修复,增加了对 ACC_SYNTHETIC 的判断,修改的地方如下:

这样,在新版本的 Spring 中,就不存在这个问题了,升级以后果然解决了问题。

Kotlin 编译器源码探秘

有了实验的结果,反过来寻找原因就很简单了,找到原因 kotlin 1.2 的源码,然后翻一翻源码,马上找到了对应的逻辑。在 4 年前的一个 commit 中,有一个伙计干掉了 ACC_BRIDGE 标记。

对应的源码修改如下

Kotlin 新版逻辑

有小伙伴又试了 kotlin 1.4+,发现问题也消失了,这又引起了我的兴趣,看了一下字节码,发现新版本的 getActivityGameByPage$default() 中,已经没有了注解,这下从源头解决了问题。

Springboot 项目不同包下,相同类名冲突导致服务启动失败 项目背景:A项目因为业务原因,需要B项目提供一个service的包,AB是两个独立的项目(不同数据源),A引入B项目的service包后,项目启动失败。 文章目录1.示例2.报错信息3.报错原因4.解决方案 1.示例 我遇到的问题: 2.报错信息 Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'RRException. 阅读详情

相关推荐

手把手教你用LIO-SAM搞定激光雷达和IMU联合标定(附避坑指南)

本文详细介绍了使用LIO-SAM进行激光雷达与IMU联合标定的全流程,包括标定原理、工具选型、硬件配置、数据采集、LI_calib标定步骤及LIO-SAM集成验证。特别提供了避坑指南和参数优化技巧,帮助开发者高效完成传感器标定,提升自动驾驶和机器人定位精度。

hadoop5ranger的博客 995

一次性解决Spring 无法启动的问题

问题背景 有同学反馈,有一个项目从 kotlin 1.2 升级到 kotlin 1.3 以后 Spring 项目无法启动,报 java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'xxx' method错误 没有引入任何其它变量,只是更改了 kotlin 的版本,猜测可能是编译出来的字节码不一样,出问题的函数如下。 @OptionalAuthAPI @GetMapping("/page") fun getActiv..

m0_67645544的博客 2172

别再只调IoU了!给YOLOv8换上NWDLoss,实测小目标检测精度提升明显

本文深入探讨了YOLOv8在小目标检测中的优化策略,重点介绍了NWDLoss(Normalized Wasserstein Distance Loss)的应用优势。通过对比实验证明,NWDLoss能有效解决传统IoU损失函数的局限性,显著提升小目标检测精度,在遥感影像和交通监控等场景中表现尤为突出。文章提供了详细的代码实现和训练技巧,帮助开发者快速集成这一先进技术。

weixin_29072299的博客 280

编译环境61.0大于运行环境52.0造成错误

解决:降低MultipleOpenApiSupportCondition类的依赖版本即可。解释:编译环境为61.0 ,运行环境为52.0,编译环境大于运行环境造成错误。

qq_47932288的博客 875

Hi3559AV100制作ext4文件系统和烧录emmc

1、首先生成所需文件系统,见本博客&lt;Hi3559AV100文件系统制作cramfs&gt;。 2、使用工具生成EXT4文件系统 ./make_ext4fs -s -l 96M rootfs_hi3559av100.ext4 ./rootfs 3、烧录文件系统 mw.b 0x82000000 ff 0x12C00000;tftp 0x82000000 STM_...

阿Sir问道 7036

zemax混合式非序列模拟

注意不要点击左侧的非序列模式,那个时纯粹的非序列,会清除序列模式的数据。第2、4、6透镜材质为空气,是为了让光线进入到多重透镜内部。这时普通的优化方式会失败。平行光束经过多焦透镜时,会汇聚在不同焦距处。所以还需要控制能量的大小,进行优化。接下来用非序列模式设计一个多焦透镜。像面的孔径为圆形通光孔:0-1.2。透镜不同位置处有不同的聚焦位置。透镜的z轴位置相同,重合。

fendoudecheng的博客 3069

springdoc-openapi 的基本使用

很多从 swagger 2 过来的用户可能会好奇,为什么不使用 springfox 库来生成 API,我在这里简单总结一下springdoc-openapi 是 spring 官方出品,与 springboot 兼容更好(springfox 兼容有坑)springdoc-openapi 社区更活跃,springfox 已经 2 年没更新了springdoc-openapi 的注解更接近 OpenAPI 3 规范。

csdn_manong1的博客 1448

华为eNSP实战:手把手教你配置DHCP全局地址池(含AP固定IP分配)

本文通过华为eNSP模拟器,详细演示了如何配置DHCP全局地址池,为不同业务VLAN动态分配IP地址,并重点讲解了如何通过MAC地址绑定为接入点(AP)分配固定IP。文章涵盖了从拓扑设计、基础网络搭建到地址池精细配置、验证测试及常见故障排查的全流程,是网络工程师掌握企业级DHCP部署与AP管理的实用指南。

weixin_29235923的博客 600

一次 Spring 无法启动的原因排查(字节码篇)

问题背景 有同学反馈,有一个项目从 kotlin 1.2 升级到 kotlin 1.3 以后 Spring 项目无法启动,报java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'xxx' method错误 没有引入任何其它变量,只更改了 kotlin 的版本,猜测可能是编译出来的字节码不一样,出问题的函数如下。 @OptionalAuthAPI @GetMapping("/page") fun getActivityG..

uuqaz的博客 1960

模板匹配加速之金字塔分层搜索

图像金字塔是一种多分辨率图像表示方法,它通过一系列逐渐缩小或放大的图像来表示原始图像的不同尺度。高斯金字塔(Gaussian Pyramid):通过不断下采样(降采样)生成更小的图像。拉普拉斯金字塔(Laplacian Pyramid):通过高斯金字塔和差分操作生成一组残差图像。在模板匹配中,我们主要使用高斯金字塔来实现多尺度匹配。金字塔灰度模板匹配通过多尺度搜索策略,在保持较高准确率的同时显著提升匹配速度,尤其适用于:高分辨率图像处理实时检测系统移动端设备等资源受限场景。

weixin_44969144的博客 1733

Gazebo手册:【1】gazebo基本操作案例

欢迎来到初学者模块!本模块将引导您了解 Gazebo 的最基本功能。我们将构建一个简单的车辆来演示这些功能。这些教程适用于 Gazebo 新手和/或没有编程或 Linux 经验的人。 每个教程都建立在上一个教程的基础上,因此我们建议您按顺序学习这些教程。 一、何为Gazebo? Gazebo 是一款 3D 动态模拟器,能够准确有效地模拟复杂室内和室外环境中的机器人种群。虽然类似于游戏引擎,但 Gazebo 提供了更高保真度的物理模拟、一套传感器以及用于用户和程序的接口。 1............

gongdiwudu的专栏 2万+

排查Spring 无法启动的问题

这几天有小伙伴跟我反馈,有一个项目从kotlin1.2升级到kotlin1.3以后Spring项目无法启动,报java.lang.IllegalStateExceptionAmbiguousmapping.Cannotmap'xxx'method错误,下面咱们一个个分析排查没有引入任何其它变量,只是更改了kotlin的版本,猜测可能是编译出来的字节码不一样,出问题的函数如下。Int=0)}...

Q54665642ljf的博客 760

别把 ABAP 时间戳当数字算:TIMESTAMP / TIMESTAMPL 的语义、正确用法与项目级避坑指南

ABAP时间戳使用指南与常见陷阱 摘要:ABAP中的时间戳(TIMESTAMP/TIMESTAMPL)本质是UTC时间的数字表示,而非累计秒数。正确用法包括:直接比较时间戳顺序、使用CONVERT TIME STAMP进行时区转换、通过CL_ABAP_TSTMP计算时间差。关键注意事项:绝对不要对时间戳本身进行数学运算,否则会导致非法时间值。实际项目中需特别注意SAP Gateway的ETag处理、跨时区系统集成和CDS视图中的时间戳使用场景,避免将本地时间误存为UTC时间戳或在云迁移时产生时区问题。(14

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 347

记录一次开发中启动遇到的jvm问题

重新构建项目,启动成功,未再出现JVM崩溃。后续运行所有涉及SQL解析的功能,均表现正常。初步分析错误日志打开:显示,说明崩溃发生在本地代码的空指针地址,通常是由于JVM内部执行某些本地操作时跳转到了非法地址。:查看当前线程的堆栈,可以看到最后执行的Java方法。这里发现堆栈中频繁出现jsqlparser相关的类名,例如等。:检查加载的本地库,未发现异常第三方本地库,排除JNI因素。猜测可能原因由于堆栈指向jsqlparser,而项目使用了进行数据库操作,其内部依赖jsqlparser解析SQL。

weixin_45099691的博客 374

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Metaspace OOM 排查实录:一次 Spring 热部署爆掉 256 M 元空间

面试答案一句话存什么?类元数据:类名、字段、方法、字节码、常量池在哪?本地内存(Native Memory),不在 Java 堆上限?默认无上限,但启动可设何时回收?类卸载时:所有实例已死 + 类加载器已死 + 无引用类加载器活着 → 它加载的所有类占用的 Metaspace 不会释放反复热部署 = 反复造新的类加载器 →Metaspace 只增不减。

持续输出Java相关知识 860

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java项目代码保护实战:ClassFinal字节码加密原理与Spring Boot集成指南

在Java开发中,代码保护是商业软件交付和核心算法保护的关键需求。其基本原理是通过对编译后的字节码进行处理,防止源代码被轻易反编译和逆向工程。从技术价值看,有效的代码保护能保障知识产权,防止核心业务逻辑泄露,尤其在SaaS服务、商业软件交付等场景中至关重要。应用场景广泛,包括金融风控系统、定价模型、商业算法等敏感项目。本文聚焦于ClassFinal这一基于Java Agent的字节码加密工具,它通过运行时动态解密机制,为Java项目提供高强度保护。相较于传统混淆,ClassFinal在防止静态反编译方面更具

weixin_34007020的博客 340

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Spring-Instrument模块:JVM字节码增强与性能监控实战

Java字节码增强技术是JVM生态中的核心能力,通过在类加载阶段修改字节码,可以实现AOP无法完成的底层功能。其原理基于Java Agent机制,通过ClassFileTransformer拦截.class文件流,配合ASM等工具进行动态修改。这种技术在性能监控、分布式追踪等场景具有不可替代的价值,特别是需要无侵入式采集方法级指标时。Spring-Instrument模块封装了这些底层能力,与Spring AOP形成互补——前者作用于类加载期,后者专注于运行时代理。典型应用包括热部署支持、方法耗时统计等场景

weixin_33857230的博客 366

Spring Boot应用防反编译实战:从代码混淆到字节码加密的纵深防御

在Java应用开发中,代码保护是保障知识产权和商业机密的关键环节。Java字节码因其易于反编译的特性,使得核心业务逻辑、算法和敏感配置面临泄露风险。其原理在于.class文件包含的字节码与源代码对应关系直接,市面上存在大量成熟的反编译工具可轻易还原。为应对这一挑战,开发者需构建从代码混淆到运行时安全的纵深防御体系,而非依赖单一加密方案。代码混淆通过重命名和流程控制变形增加阅读难度,而字节码加密则通过自定义类加载器在运行时动态解密,从物理层面保护原始字节码。这两种技术结合,能有效提升逆向工程门槛,适用于对代码

457

【实战JVM】字节码常用工具分享

玩转字节码常用工具 javap javap是JDK自带的反编译工具,可以通过控制台查看字节码文件的内容。适合在服务器上查看字节码文件内容。 直接输入javap查看所有参数。输入javap -v 字节码文件名称 查看具体的字节码信息。如果jar包需要先使用 jar –xvf 命令解压。

鱼干的博客 2828

Spring Boot应用JAR加密实战:从字节码加密到自定义类加载器

在Java应用开发中,源码保护是商业化项目面临的核心挑战之一。Java字节码因其易于反编译的特性,使得核心业务逻辑面临泄露风险。其原理在于JVM加载的是.class文件,而市面上常见的反编译工具可以轻易将其还原为可读代码。为了保护知识产权和商业机密,对编译后的字节码进行加密处理成为一项关键技术。通过实现自定义类加载器,可以在类加载阶段动态解密字节码,从而在不影响应用正常运行的前提下,有效防止反编译。这项技术在需要交付给客户的商业化Spring Boot应用、SaaS产品以及外包项目中具有重要价值,能够为企业

weixin_34060299的博客 466

Spring-Instrument模块:LTW技术与字节码增强实践

Java字节码增强技术是JVM生态中的重要能力,通过修改类加载阶段的字节码实现无侵入式功能扩展。其核心原理基于Java Agent机制和Instrumentation API,允许开发者在类加载时动态插入监控、性能分析等逻辑。相比传统运行时AOP,加载时织入(LTW)技术具有零运行时开销、支持final方法增强等优势,特别适合APM系统、ORM延迟加载等高性能场景。Spring-Instrument模块封装了底层复杂性,结合AspectJ可实现细粒度切面编程。典型应用包括Skywalking全链路监控、Hi

weixin_29698641的博客 191

【JVM操作字节码文件流程详解】

摘要: 本文详解JVM操作字节码文件的完整流程,揭示Java跨平台特性的实现原理。核心流程分为加载(双亲委派机制)、验证(安全校验)、准备(静态变量默认值分配)、解析(符号引用转直接引用)和初始化(执行静态代码)五个关键步骤。重点分析了字节码执行阶段解释执行与JIT编译的协同机制,以及热点代码判定标准。通过实际场景(如Spring Boot服务启动、接口调用优化)说明各阶段作用,并解答类初始化触发条件、JIT调优等典型问题,帮助开发者深入理解JVM运行机制与性能优化要点。(149字)

2401_82641862的博客 679
上一篇: 设计模式学习笔记:观察者模式及应用场景
下一篇: 重新刷新你对Redis集群的理解
JavaShark
博客等级 码龄4年 184粉丝 438原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值