最近在做一个远程项目,应用在本地idea和远程同事的idea中能够跑起来,但是同事那边使用Jenkins打包部署到服务器之后,启动报错,日志报错信息如下图所示:
这个报错是类加载时的校验阶段出错,和字节码有关,不过既然本地能够启动,很自然的觉得应该是JDK版本有差异,从而导致字节码不兼容。查看了JDK版本,我自己和同事的版本分别是1.8.0_181与1.8.0_271,而服务器上面是1.8.0_101版本。
由于服务器版本无法改变,那么只能寻找修改代码的方法了,又仔细看了一下错误信息,发现了invokedynamic与lamda这两个关键字,lamda表达式是JDK8加入的语法糖,运行时通过invokedynamic指令实现功能,所以将代码中的lamda表达式进行修改,换成了不使用lamda的实现,重新打包之后,放在服务器上成功运行。
备注:解决问题的过程实际麻烦得多,经过了一系列的心路历程:
(1)最开始怀疑JDK版本问题,觉得服务器上可能使用的是OpenJDK,经过查看之后,发现服务器上用的也是OracleJDK。
(2)验证了服务器上用的不是OpenJDK之后,我开始怀疑是lamda表达式的问题,这个判断基于在《深入理解Java虚拟机》一书中学到的知识,以及脑子里面隐隐约约记得看到过1.8的lamda表达式导致其它BUG博客,为了确认这一点,我开始在baidu上搜索。
(3)很遗憾,搜索关键字不精确(只使用了"bad type on operand stack")让我走了很大的弯路,很多人说这个错误产生的原因是依赖的库版本不对,刚好我这个项目也有一个公共common包的依赖问题,由于是远程开发,自己搭建环境的时候选择的common包版本和对方使用的版本不一样,所以在这一步尝试了很多方法,也都没有解决。
(4)最后还是回到lamda表达式,在StackOverflow上搜索到几篇关于lamda与VerifyError的提问(链接在下面),于是我选择了将代码修改为非lamda表达式的实现,问题解决。