我有两个不同的webapps,每个都加载相同的A类和不同的classloader。当我在会话中放入一个实例然后从另一个webapp获取它时,会抛出ClassCastException
。
例如,在webapp A中,我将a
存储在会话中,然后在webapp B中,我从会话中获取a
并将其转换为A,ClassCastException
为抛出。
有没有办法解决这个问题?
答案 0 :(得分:5)
有没有办法解决这个问题?
基本上没有。
就JLS而言,类型是不同的类型,并且JVM无法允许您以其他方式伪装。例如,类可以具有不同的代码和不同的对象布局。如果您可以欺骗JVM将类型视为相同,那么您将能够吹走JVM运行时的安全性。那种方式就是精神错乱。
解决方案是确保您没有两个不同的类加载器加载同一个类。在Tomcat的上下文中,这意味着如果两个或更多webapp需要共享一个类的实例,那么该类必须在两个共同的类加载器中定义;例如将JAR文件放在$CATALINA_HOME/lib
或$CATALINA_HOME/common
目录中。
如果有一个合理的原因,为什么类有要由不同的类加载器加载(可能因为这些类确实不同),那么你可以通过定义一个接口来解决这个问题类实现,然后编程到接口而不是实现类。当然,只能加载一个版本的接口......否则你会再遇到同样的问题。
答案 1 :(得分:3)
基本上应该避免这种情况 - 要么将两个功能位放在同一个webapp中,要么将包含A类的库移动到适当的位置,这样只使用一个类加载器。不同类加载器加载的两个类在JVM中是完全不同的 - 你只是不能能够在它们之间进行转换。
有关使用的各种类加载器的更多详细信息,请参阅Tomcat classloader documentation。看起来你想把这个普通的类放到公共的类加载器区域。正如文档所述,这是非常不寻常的,但是如果你真的想要在两个webapps之间共享一个对象(也不寻常),这可能是最简单的前进方式。 / p>
答案 2 :(得分:1)
你做不到。不同类加载器加载的两个类是不同的。
答案 3 :(得分:0)
也许您可以序列化共享对象?
我不一定提倡这种方法,但是那就是序列化本质上做的 - 你从一些JVM或ClassLoader序列化 X 并将其加载(反序列化)到另一个JVM / ClassLoader Y ...
答案 4 :(得分:0)
即使类具有相同的包名称和签名,也不能从不同的类转换两个对象,但是只需使用apache bean utils库BeanUtils.copyProperties(o1, o2);
即可将数据从一个复制到另一个
答案 5 :(得分:0)
这可以通过解决方法实现。
虽然你不能将一个对象从类加载器A加载的类转换为类加载器B加载的同一个类(如果在不同的类加载器下加载explained here,那么具有相同名称的类不兼容),在诸如Jetty或Tomcat之类的webapp容器中,您可以在父类加载器中加载该类一次,这将由JVM中的所有Web应用程序使用。每个webapp类加载器都将遵循类定义的共享(父)类加载器,并且来回运行就可以了。
例如,使用Jetty,使用here所述的WebAppContext.addSystemClass()
。