最近看了几天的问题,Google、文档后无果,来论坛上请教是否有人有解决思路。
我们使用 k8s host 某个 Java 项目,使用 jetty,项目通过 maven 管理依赖。之前一直正常,但最近遇到问题。 神奇的是,即使是同一份 image,每次 set 之后的表现也会不同。有时一切正常,有时则会在调用特定方法时抛出如下异常。 java.lang.NoSuchMethodError: com.google.common.base.Stopwatch.elapsed()Ljava/time/Duration;
这个问题看起来是项目中不同模块依赖不同的 guava 版本所致。一个我们依赖的第三方包需要依赖 22.0 版本的 guava,但其他一些依赖会找到比较老的版本。那些老版本缺少 elapsed() 方法。为此,我们在数月前曾经通过 shade 的 plugin 让依赖该包的项目始终使用 22.0 版本。一切相安无事。 最近两周,突然开始出现 mvn package 并 build 成 docker image 后放到 k8s 上,会随机发生上述异常。检查了编译结果,似乎和以前没有区别。至少,在需要依赖 22.0 版本的项目 jar 包中,guava 22.0 依然被 shade。 使用更新版本的 guava 似乎可以解决这个问题,但这显然掩盖了问题的根本原因。
有怀疑过 k8s 是否会缓存一些依赖,但看起来又不像,也查不到类似的文档。
不知诸位对这个问题有何高见?
1
Ley OP 最后通过增加额外逻辑在 class loader 打印出 classpath 发现了问题所在。
原因是某个 Apache 的依赖内直接包装了老版本的 com.google.common.base.Stopwatch,因此在 mvn 的 dependency tree 中不会被列出。然后在 Jetty 的 embeded server 中 load class 时会在 mvn 中的版本和这个老版本中随机选择一个。如果选中了不包含 elapsed()Ljava/time/Duration 的版本,就会抛出异常。 由于该 Apache 依赖仅用于单元测试,将其 dependency scope 改为 test 便解决问题。 |