重新部署项目后,存储在会话中的对象将不匹配 class
Object stored in session will not match same class after redeploy of project
我有两个 class 扩展 WaterBody
的 Stream
和 Lake
。 Stream
或 Lake
存储在 Apache Shiro 1.2.4 管理的会话中,以备后用。
WaterBody lake = new Lake();
session.setAttribute("water", lake);`
并使用
检索它
WaterBody water = (WaterBody) session.getAttribute("water");
在重新启动 Wildfly 9.0.2 服务器时,我可以将对象存储到会话中并检索它们。我是否将 Lake
或 Stream
存储到 water
会话属性并不重要。但是,在不重新启动 Wildfly 服务器的情况下重新部署项目后,我可以将与以前相同的 class 类型存储到会话属性 water
即:不能先存储 Lake
然后重新部署商店 Stream
。我收到此错误:
java.lang.ClassCastException: cannot assign instance of [Lfwp.fish.water.HydroUnit; to field fwp.fish.water.WaterBody.hucs of type [Lfwp.fish.water.HydroUnit; in instance of fwp.fish.water.Stream
class WaterBody
具有类型为 HydroUnit
的私有字段的 getter 和 setter,因为这是由 Stream
和 Lake
继承的错误没有意义。
如果重新开始,water
会话属性在重新部署之前和之后都分配给了相同的 class,它将把值分配给会话变量就好了,然后在检索它时会抛出这个错误:
java.lang.ClassCastException: fwp.fish.water.Lake cannot be cast to fwp.fish.water.WaterBody
因为 Lake
扩展了 WaterBody
它应该没有问题。
对于 Shiro,我们使用 ehcache 2.9 作为会话缓存。
似乎 serialVersionUID
被缓存忽略了,或者它在幕后生成了一个不同的缓存,并且它认为 classes 在重新部署之间没有变化时已经发生了变化。
class是:
public class WaterBody implements Serializable {
private static final long serialVersionUID = -5481729151007010163L;
private int id;
private HydroUnit[] hucs;
public WaterBody() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public HydroUnit[] getHucs() {
return hucs;
}
public void setHucs(HydroUnit[] hucs) {
this.hucs = hucs;
}
}
public class Lake extends WaterBody {
private static final long serialVersionUID = -925557850476426686L;
private String centroidLatitude;
private String centroidLongitude;
public Lake(){
super();
}
public String getCentroidLatitude() {
return centroidLatitude;
}
public void setCentroidLatitude(String centroidLatitude) {
this.centroidLatitude = centroidLatitude;
}
public String getCentroidLongitude() {
return centroidLongitude;
}
public void setCentroidLongitude(String centroidLongitude) {
this.centroidLongitude = centroidLongitude;
}
}
public class Stream extends WaterBody {
private static final long serialVersionUID = 2556033593701784053L;
private String mouthLatitude;
private String mouthLongitude;
public Stream(){
super();
}
public String getMouthLatitude() {
return mouthLatitude;
}
public void setMouthLatitude(String mouthLatitude) {
this.mouthLatitude = mouthLatitude;
}
public String getMouthLongitude() {
return mouthLongitude;
}
public void setMouthLongitude(String mouthLongitude) {
this.mouthLongitude = mouthLongitude;
}
}
在研究这个问题之后,我们发现了这个问题。当项目 运行 第一次 ClassLoader
创建 类 时使用它们,然后将对象存储到会话中。在服务器为 运行 时对该项目进行热重新部署后,当它再次加载 Class
时,ClassLoader
会创建该 Class
的新实例。但是,会话仍然记得上次存储 Class
的对象时的 Class
,并且有时会让新对象存储在会话中,显示为同一对象。但是在检索对象时,它仍然由 Class
的旧实例定义,因此当试图将其转换为 Class
的当前实例时,它将失败。
我们的解决方案是针对在会话中存储对象的项目,将将作为对象存储在会话中的 类 分离到项目中包含的单独 .jar
模块中被重新部署。这样一来,如果 Class
文件发生更改,服务器将不得不重新启动,因为模块依赖性发生了更改。现在,如果项目是热重新部署的,类 保持不变,因为它们不在正在刷新的 .war
文件中。
我有两个 class 扩展 WaterBody
的 Stream
和 Lake
。 Stream
或 Lake
存储在 Apache Shiro 1.2.4 管理的会话中,以备后用。
WaterBody lake = new Lake();
session.setAttribute("water", lake);`
并使用
检索它WaterBody water = (WaterBody) session.getAttribute("water");
在重新启动 Wildfly 9.0.2 服务器时,我可以将对象存储到会话中并检索它们。我是否将 Lake
或 Stream
存储到 water
会话属性并不重要。但是,在不重新启动 Wildfly 服务器的情况下重新部署项目后,我可以将与以前相同的 class 类型存储到会话属性 water
即:不能先存储 Lake
然后重新部署商店 Stream
。我收到此错误:
java.lang.ClassCastException: cannot assign instance of [Lfwp.fish.water.HydroUnit; to field fwp.fish.water.WaterBody.hucs of type [Lfwp.fish.water.HydroUnit; in instance of fwp.fish.water.Stream
class WaterBody
具有类型为 HydroUnit
的私有字段的 getter 和 setter,因为这是由 Stream
和 Lake
继承的错误没有意义。
如果重新开始,water
会话属性在重新部署之前和之后都分配给了相同的 class,它将把值分配给会话变量就好了,然后在检索它时会抛出这个错误:
java.lang.ClassCastException: fwp.fish.water.Lake cannot be cast to fwp.fish.water.WaterBody
因为 Lake
扩展了 WaterBody
它应该没有问题。
对于 Shiro,我们使用 ehcache 2.9 作为会话缓存。
似乎 serialVersionUID
被缓存忽略了,或者它在幕后生成了一个不同的缓存,并且它认为 classes 在重新部署之间没有变化时已经发生了变化。
class是:
public class WaterBody implements Serializable {
private static final long serialVersionUID = -5481729151007010163L;
private int id;
private HydroUnit[] hucs;
public WaterBody() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public HydroUnit[] getHucs() {
return hucs;
}
public void setHucs(HydroUnit[] hucs) {
this.hucs = hucs;
}
}
public class Lake extends WaterBody {
private static final long serialVersionUID = -925557850476426686L;
private String centroidLatitude;
private String centroidLongitude;
public Lake(){
super();
}
public String getCentroidLatitude() {
return centroidLatitude;
}
public void setCentroidLatitude(String centroidLatitude) {
this.centroidLatitude = centroidLatitude;
}
public String getCentroidLongitude() {
return centroidLongitude;
}
public void setCentroidLongitude(String centroidLongitude) {
this.centroidLongitude = centroidLongitude;
}
}
public class Stream extends WaterBody {
private static final long serialVersionUID = 2556033593701784053L;
private String mouthLatitude;
private String mouthLongitude;
public Stream(){
super();
}
public String getMouthLatitude() {
return mouthLatitude;
}
public void setMouthLatitude(String mouthLatitude) {
this.mouthLatitude = mouthLatitude;
}
public String getMouthLongitude() {
return mouthLongitude;
}
public void setMouthLongitude(String mouthLongitude) {
this.mouthLongitude = mouthLongitude;
}
}
在研究这个问题之后,我们发现了这个问题。当项目 运行 第一次 ClassLoader
创建 类 时使用它们,然后将对象存储到会话中。在服务器为 运行 时对该项目进行热重新部署后,当它再次加载 Class
时,ClassLoader
会创建该 Class
的新实例。但是,会话仍然记得上次存储 Class
的对象时的 Class
,并且有时会让新对象存储在会话中,显示为同一对象。但是在检索对象时,它仍然由 Class
的旧实例定义,因此当试图将其转换为 Class
的当前实例时,它将失败。
我们的解决方案是针对在会话中存储对象的项目,将将作为对象存储在会话中的 类 分离到项目中包含的单独 .jar
模块中被重新部署。这样一来,如果 Class
文件发生更改,服务器将不得不重新启动,因为模块依赖性发生了更改。现在,如果项目是热重新部署的,类 保持不变,因为它们不在正在刷新的 .war
文件中。