2

在我们的 WAR 中,我们有三个包含类的 JAR org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager。一个 jar 的版本比其他的旧。

这不会在我们的开发或暂存环境中导致问题,但是在我们的生产环境中,加载了来自不同 JAR 的类的版本,导致我们java.lang.NoSuchMethodError启动时出现问题。我采用了在生产中失败的完全相同的 WAR,并在阶段和开发中成功运行它。

在 Java 中,是什么决定了选择哪个 jar 版本的类?是什么导致一个盒子与另一个盒子不同?

4

3 回答 3

3

您永远无法知道 Classloader 将按什么顺序加载 jar [您可以使用选项来可视化它-verbose:class] 或修改它。因此,既然您知道 2 个 jar 具有相同文件的问题,那么只需放置正确的 jar,否则无论您是否出错,这只是运气。

编辑:您还可以检查这个问题如何查找类加载器加载哪些罐子以及按什么顺序加载?

于 2013-06-26T16:03:44.187 回答
2

Loki 是对的,结论也一样:必须重新审视战争的包装。您不能让同一个类加载器加载三个相同命名的类,并保证首先加载哪个类。

每个 servlet 容器,例如 Jetty、Tomcat(您没有指定使用哪个容器)都重新实现了某种方式webappClassLoader以保证 - 根据 servlet 规范 2.5+ - 战争中提供的 jar 的类优先加载那些父类加载器。这是与 Java 提供的 ÙRLClassLoader 的主要区别,后者首先搜索父类加载器。servlet 规范没有详细说明应该如何进行搜索。

换句话说,如果您更改 servlet 容器或仅更改 servlet 容器的版本,则您的战争行为可能会再次发生变化。底层文件系统也可能会产生影响(区分大小写/不区分大小写)等......

==> 你必须重新包装你的战争。

假设你使用的是Tomcat 7,这里是findClassTomcat WebappClassLoader方法的链接

于 2013-06-29T06:06:43.967 回答
0

jar 加载顺序由文件系统决定。如果文件系统中的默认顺序更改,则加载顺序会更改。文件系统的顺序由操作系统决定,至少在某些操作系统上,最终的创建顺序决定了加载顺序。请注意,这不是文件的创建日期,而是在文件系统上创建文件的实际时间。因此,您可以拥有外观相同的文件系统,它们在 jar 加载中表现出不同的行为。最终没有控制顺序的好方法,因此您要重新确保在类路径中没有不同版本的相同 jar。

于 2016-03-07T18:59:13.887 回答