How to cast two instance of the same loaded different classloader?

独自空忆成欢 提交于 2020-01-01 09:08:08

问题


I have two different webapps, and each load the same class A with different classloader. When I put one instance in the session and then get it from the other webapp, a ClassCastException is thrown.

For example, in webapp A, I store a in the session, then in webapp B, I get the a from the session and cast it to A, the ClassCastException is thrown.

Is there a way to resolve this?


回答1:


Is there a way to resolve this?

Basically no.

As far as the JLS is concerned, the types are different types, and there is no way that the JVM will allow you to pretend otherwise. For instance, the classes could have different code and different object layouts. If you could trick the JVM into treating the types as the same, you would be able to blow away JVM runtime safety. That way lies insanity.

The solution is to make sure that you don't have two different class loaders loading the same class. In the context of Tomcat, this means that if two or more webapps need to share instances of a class, then that class must be defined in a classloader that is common to both; e.g. put the JAR file in the $CATALINA_HOME/lib or $CATALINA_HOME/common directory.


If there is a sound reason why the classes have to be loaded by different classloaders (maybe because the classes really are different), then you could workaround the problem by defining an interface that both versions of the class implement, and then programming to the interface rather than the implementation class. Of course, there can only be one version of that interface loaded ... or else you run into the same problem again.




回答2:


You should avoid this situation, basically - either put both bits of functionality in the same webapp, or move the library containing class A into an appropriate location such that only one classloader will be used. Two classes loaded by different classloaders are entirely distinct in the JVM - you simply won't be able to cast between them.

See the Tomcat classloader documentation for more details about the various classloaders used. It looks like you'd want to put this common class into the common classloader area. As the documentation notes, this is pretty unusual, but if you really want to share an object between two webapps (which is also unusual) it's probably the easiest way forward.




回答3:


You can't. Two classes loaded by different classloaders are different.




回答4:


Perhaps you can serialize the shared objects?

I'm not necessarily advocating this approach, but then again that's what serialization essentially does --- you serialize from some JVM or ClassLoader X and load it in (deserialize) it into another JVM/ClassLoader Y...




回答5:


You can't cast two object from different classes even if the classes have the same package name and signature, however you can copy the data from one to another simply by using apache bean utils library, BeanUtils.copyProperties(o1, o2);




回答6:


This is possible with a workaround.

While it is true that you can't cast an object from one class loaded by classloader A to the same class loaded by classloader B (classes with the same name are not compatible if loaded under different classloaders as explained here), in a webapp container such as Jetty or Tomcat, you can load that class once in a parent classloader, which will be used by all webapps in the JVM. Each webapp classloader will defer to the shared (parent) classloader for the class definition and casting it back and forth works just fine.

For example, with Jetty, use WebAppContext.addSystemClass() as described here.



来源:https://stackoverflow.com/questions/10569952/how-to-cast-two-instance-of-the-same-loaded-different-classloader

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!