如何构建同一个加载不同类加载器的两个实例?
我有两个不同的webapps,每个都加载相同的A类和不同的类加载器。 当我在会话中放入一个实例然后从另一个webapp获取它时, ClassCastException
。
例如,在webapp A中,我在会话中存储a
,然后在webapp B中,我从会话中获取a
并将其转换为A, ClassCastException
。
有办法解决这个问题吗?
有办法解决这个问题吗?
基本上没有。
就JLS而言,类型是不同的类型,并且JVM不允许您以其他方式伪装。 例如,类可以具有不同的代码和不同的对象布局。 如果您可以欺骗JVM将类型视为相同类型,那么您将能够吹走JVM运行时的安全性。 那种方式就是精神错乱。
解决方案是确保您没有两个不同的类加载器加载相同的类。 在Tomcat的上下文中,这意味着如果两个或更多webapps需要共享一个类的实例,那么该类必须在两个共同的类加载器中定义; 例如,将JAR文件放在$CATALINA_HOME/lib
或$CATALINA_HOME/common
目录中。
如果有一个合理的原因,为什么类必须由不同的类加载器加载(可能因为类真的不同),那么你可以通过定义类的两个版本实现的接口,然后编程到接口来解决问题而不是实现类。 当然,只能加载一个版本的接口…否则你会再次遇到同样的问题。
您应该避免这种情况,基本上 – 要么将两个function位置放在同一个webapp中,要么将包含A类的库移动到适当的位置,这样只使用一个类加载器。 不同类加载器加载的两个类在JVM中完全不同 – 您根本无法在它们之间进行转换。
有关使用的各种类加载器的更多详细信息,请参阅Tomcat类加载器文档 。 看起来你想把这个普通的类放到公共的类加载器区域。 正如文档所述,这是非常不寻常的,但如果你真的想在两个webapps之间共享一个对象(这也很不寻常),那么这可能是最简单的方法。
你不能。 由不同类加载器加载的两个类是不同的。
也许你可以序列化共享对象?
我不一定提倡这种方法,但是这又是序列化本质上做的 – 你从一些JVM或ClassLoader X序列化并将其加载(反序列化)到另一个JVM / ClassLoader Y …
即使类具有相同的包名和签名,也不能从不同的类中转换两个对象,但是只需使用apache bean utils库, BeanUtils.copyProperties(o1, o2);
就可以将数据从一个复制到另一个BeanUtils.copyProperties(o1, o2);
这可以通过解决方法实现。
虽然你不能将一个对象从类加载器A加载的一个类转换为类加载器B加载的同一个类(如果在不同的类加载器下加载,如同在这里解释的那样具有相同名称的类不兼容),则在webapp容器中例如Jetty或Tomcat,您可以在父类加载器中加载该类一次,这将由JVM中的所有Web应用程序使用。 每个webapp类加载器都将遵循类定义的共享(父)类加载器,并且来回转换它可以正常工作。
例如,使用Jetty,请使用此处所述的WebAppContext.addSystemClass()
。
- ClassCastException将List 转换为Class
- 在进行通用转换时,在generics方法中捕获ClassCastException
- Java:未选中从X转换为Y /如何实现castOrNull
- 引起:java.lang.ClassCastException:java.sql.Timestamp无法强制转换为java.sql.Date
- 签名小程序和服务器端控制器之间的通信
- 附加对象OutputStream时的ClassCastException
- 将HashMap值添加到TreeSet时出错
- 这有什么不对? 我得到一个java.lang.ClassCastException错误,但我看不出我出错的地方
- 由于ClassLoader问题导致ClassCastException的解决方案