9

我有两个不同的网络应用程序,每个应用程序都使用不同的类加载器加载相同的 A 类。当我将一个实例放入会话中,然后从另一个 web 应用程序中获取它时,ClassCastException会抛出 a。

例如,在 webapp A 中,我存储a在会话中,然后在 webapp B 中,我a从会话中获取并将其转换为 A,然后ClassCastException抛出。

有没有办法解决这个问题?

4

6 回答 6

6

有没有办法解决这个问题?

基本上没有。

就 JLS 而言,类型是不同的类型,JVM 不会允许您假装其他类型。例如,这些类可能有不同的代码和不同的对象布局。如果您可以欺骗 JVM 将类型视为相同,您将能够吹走 JVM 运行时安全性。那就是精神错乱。

解决方案是确保您没有两个不同的类加载器加载同一个类。在 Tomcat 的上下文中,这意味着如果两个或多个 webapps 需要共享一个类的实例,那么该类必须在两者都通用的类加载器中定义;例如,将 JAR 文件放在$CATALINA_HOME/libor$CATALINA_HOME/common目录中。


如果由于技术原因必须由不同的类加载器加载类(可能是因为类确实不同),那么您可以通过定义两个版本的类都实现的接口来解决该问题,然后编程到接口而不是实现类。当然,接口需要由共享类加载器加载……否则你会再次遇到同样的问题。

于 2012-05-13T07:24:37.873 回答
3

基本上,您应该避免这种情况 - 要么将这两种功能放在同一个 webapp 中,要么将包含类 A 的库移动到适当的位置,以便只使用一个类加载器。由不同类加载器加载的两个类在 JVM 中是完全不同的——您根本无法在它们之间进行转换。

有关使用的各种类加载器的更多详细信息,请参阅Tomcat 类加载器文档。看起来您希望将此公共类放入公共类加载器区域。正如文档所述,这很不寻常,但如果你真的想在两个 web 应用程序之间共享一个对象(这很不寻常),这可能是最简单的方法。

于 2012-05-13T07:20:30.913 回答
1

你不能。不同类加载器加载的两个类是不同的。

于 2012-05-13T08:23:18.940 回答
0

也许您可以序列化共享对象?

我不一定提倡这种方法,但是这就是序列化本质上所做的——你从一些 JVM 或 ClassLoader X序列化并将其加载(反序列化)到另一个 JVM/ClassLoader Y ...

于 2013-10-31T06:38:50.013 回答
0

即使类具有相同的包名称和签名,您也不​​能从不同的类中转换两个对象,但是您可以简单地使用 apache bean utils 库将数据从一个复制到另一个,BeanUtils.copyProperties(o1, o2);

于 2015-04-23T23:59:34.153 回答
0

这可以通过一种解决方法来实现。

虽然确实不能将对象从类加载器 A 加载的一个类转换为类加载器 B 加载的同一个类(如果在不同的类加载器下加载,同名的类不兼容,如此处所述),在 webapp 容器中例如 Jetty 或 Tomcat,您可以在父类加载器中加载该类一次,该类将被 JVM 中的所有 webapps 使用。每个 webapp 类加载器都将遵循类定义的共享(父)类加载器,并且来回转换它就可以了。

例如,对于 Jetty,请WebAppContext.addSystemClass()按照此处所述使用。

于 2017-10-27T05:14:48.390 回答