在我们的WAR中我们有三个包含类org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
的JAR。一个jar的版本比其他版本旧。
这不会在我们的开发或登台环境中造成问题,但是在我们的生产环境中,加载了来自不同JAR的类的版本,导致我们在启动时java.lang.NoSuchMethodError
。我采用了与生产失败完全相同的WAR,并在舞台和开发中成功运行。
在Java中,是什么决定了选择哪个类的jar版本?什么会导致一个盒子与另一个盒子不同?
答案 0 :(得分:3)
您永远无法找到Classloader将以哪种顺序加载jar [您可以使用选项-verbose:class
]将其可视化或修改它。
所以既然你知道2个罐子有相同文件的问题,那么只需放置正确的罐子,只要你得到错误就可以得到错误。
编辑:您还可以查看此问题How to find which jars and in what order are loaded by a classloader?
答案 1 :(得分:2)
Loki是对的,结论将是相同的:必须重新审视你的战争包装。您不能通过相同的类加载器加载三个相同的命名类,并保证首先加载哪个类。
每个servlet容器,例如Jetty,Tomcat(你没有指定你正在使用哪个btw)重新实现某种webappClassLoader
以保证 - 根据servlet规范2.5+ - 提供的jar类在war中加载优先于父类加载器的加载。这是与Java提供的ÙRLClassLoader`的主要区别,它首先搜索父类加载器。 servlet规范没有详细说明应该如何进行搜索。
换句话说,如果更改servlet容器或仅更改servlet容器的版本,则战争的行为可能会再次发生变化。底层文件系统也可能有影响(区分大小写/不区分大小写等)......
==>你必须重新包装你的战争。
假设您使用Tomcat 7,这里是指向findClass
method of Tomcat WebappClassLoader
答案 2 :(得分:0)
Jar加载顺序由文件系统决定。如果文件系统中的默认顺序发生更改,则加载顺序会更改。文件系统顺序由OS确定,并且至少在某些操作系统上,最终创建的顺序决定了加载顺序。请注意,这不是文件的创建日期,而是文件系统上创建文件的实际时间。因此,您可以拥有相同的文件系统,它们在jar加载中表现出不同的行为。 最终控制订单并不是一个好方法,因此您要回到确保在类路径中没有相同的不同版本的罐子。