Docker主机之间的Java类路径排序不一致

时间:2018-12-05 15:27:18

标签: java docker classpath classloader urlclassloader

我正在Docker镜像中运行Java服务,该镜像执行以下操作:

java -server -cp 'libs/*'

奇怪的是,我发现它会在我的本地计算机上启动,而不是在开发服务器上启动,而该服务器会给出NoSuchMethodError

经过一番挖掘,我发现libs目录中同时存在JPA的2.0版和2.1版。虽然这本身就是一个问题(并且很容易解决),但是它并不能解释不一致的问题,因此我决定打印出来:

(ClassLoader.getSystemClassLoader() as URLClassLoader).urLs
    .forEach(::println) // kotlin

我发现两台机器上的lib顺序不同。但是,同一台机器上的后续图像运行之间是一致的,所以不是随机的。

尽管我现在知道为什么映像无法在开发服务器上启动,而且我可以解决当前的问题,但我的确在想:为什么这个顺序在Docker主机之间不一致?可重现性和一致性不是Docker的重点之一吗?类路径的顺序是否可以取决于IP,主机名或已安装的主机目录(在无关位置)之类的挑剔因素?

1 个答案:

答案 0 :(得分:0)

我只是碰到了这一点,发现JVM使用了一种解决类路径上通配符的方法,该方法不提供任何顺序保证。

请注意,它使用call to readdir对通配符表示的内容进行迭代,并且readdir不保证任何特定顺序:

连续调用readdir()读取文件名的顺序取决于文件系统的实现;名称不太可能以任何方式排序。

可以通过在类路径上显式排序jar而不是使用通配符来避免排序问题。在我们的案例中,我们在发现主机系统的特定差异(从readdir产生不同结果)之前删除了重复的jar。