论坛首页 Java企业应用论坛

咨询大家一个tomcat集群 memcached反序列化自定义对象的问题

浏览 9199 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-11-22  
我说下我的操作流程:
目前用的是tomcat集群 + memcached 来达到共享session的目的.
现在出现了一个问题,就是当我在不重启tomcat服务器的情况下发布一个javaBean,这个时候含有该javaBean的项目会自动重新加载,这里没有错,问题就来了加载完成后我访问JSP发现从memcached中取得的session对象中的自定义对象不能转换了见下面的异常信息:
org.apache.jasper.JasperException: java.lang.ClassCastException: com.bo.UserInfo cannot be cast to com.bo.UserInfo
	org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:522)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:416)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)


上面的问题我专门比较了classLoader
//这时的session对象是从memcached获得的,因为项目重新加载了,之前的session已经全部没了,然后我用取出的对象的class和当前这个class进行了比较结果返回的是false,说明是不一样的.

//然后我又进行了测试,发布完JAVABEAN以后重启集群中的所有tomcat服务器,然后再次访问这次对象转换是正常的,下面的代码(两个classloader返回的是true)返回的是true
Object obj = session.getAttribute("USER_PO");
System.out.println("Classloader是否一样: "+obj.getClass().getClassLoader().equals(UserInfo.class.getClassLoader()));
UserInfo uid = (UserInfo) obj;


有没有弄过的朋友,帮我看看这个问题!
关键就是不重启tomcat发布javabean和发布完javabean后,重启tomcat。从memcached取得的session中的自定义对象 前者不能转换 classLoader不同 后者可以直接使用并且classLoader相同.

很奇怪同样都是从memcached反序列化 为什么会这样?
难道重启后classLoader 有什么区别?
   发表时间:2012-11-22   最后修改:2012-11-23

你这个问题在Servlet规范中有描述:

 

 

尽管容器供应商不需要实现类的重新加载(reload)模式以便易于开发,但是任何此类的实现必须确保所有servlet及它们使用的类(Servlet使用的系统类异常可能使用的是一个不同的class loader)在一个单独的class loader范围内被加载。为了保证应用像开发人员预期的那样工作,该要求是必须的。作为一个开发辅助,容器应支持到session绑定到的监听器的完整通知语义以用于当class重新加载时session终结的监控。

之前几代的容器创建新的class loader来加载servlet,且与用于加载在servlet上下文中使用的其他Servlet或类的class loader是完全不同的。这可能导致servlet上下文中的对象引用指向意想不到的类或对象,并引起意想不到的行为。为了防止因创建新的class loader所引起的问题,该要求是必须的。

 

还有如下这篇帖子也提到过你的问题:

http://www.iteye.com/topic/31888 

 

换衣是reload造成的,两个对象的classloader不一样。

 

建议:

1、session中只存user id

2、把User对象放到tomcat/lib中 这样加载时使用的是共享的classloader。

3、禁用热部署,改后重启

0 请登录后投票
   发表时间:2012-11-23  
如果UserInfo实现序列化接口会不会有问题?
0 请登录后投票
   发表时间:2012-11-23  
luciferdevil 写道
如果UserInfo实现序列化接口会不会有问题?

肯定都是实现了序列化接口的撒! 问题不是这里,现在说的是 classLoader 单独重新加载项目应用和重启tomcat服务器会导致不一样,由于热发布项目只是重新加载了当前项目的程序,而整个tomcat容器级别的仍然保存的是之前没发布项目时的classLoader,老得classLoader没有新的Class所以被判断为了2个不同的对象.导致不能加载新Class时出现类型转换错误.

我还在研究中,不过估计问题就在这里了,重启tomcat是对的 因为整个又把每个项目又加载了一次
0 请登录后投票
   发表时间:2012-11-23  
序列话对象不要加@SuppressWarnings("serial")注释,加上private static final long serialVersionUID = -1L;或者其他数字规定序列ID,保证每个tomcat里面的同一个对象序列ID一样就没问题了。eclipse可以自动生成的。
0 请登录后投票
   发表时间:2012-11-23  
jinnianshilongnian 写道

你这个问题在Servlet规范中有描述:

 

 

尽管容器供应商不需要实现类的重新加载(reload)模式以便易于开发,但是任何此类的实现必须确保所有servlet及它们使用的类(Servlet使用的系统类异常可能使用的是一个不同的class loader)在一个单独的class loader范围内被加载。为了保证应用像开发人员预期的那样工作,该要求是必须的。作为一个开发辅助,容器应支持到session绑定到的监听器的完整通知语义以用于当class重新加载时session终结的监控。

之前几代的容器创建新的class loader来加载servlet,且与用于加载在servlet上下文中使用的其他Servlet或类的class loader是完全不同的。这可能导致servlet上下文中的对象引用指向意想不到的类或对象,并引起意想不到的行为。为了防止因创建新的class loader所引起的问题,该要求是必须的。

 

还有如下这篇帖子也提到过你的问题:

http://www.iteye.com/topic/31888 

 

换衣是reload造成的,两个对象的classloader不一样。

 

建议:

1、session中只存user id

2、把User对象放到tomcat/lib中 这样加载时使用的是共享的classloader。

3、禁用热部署,改后重启

 

基本搞明白你的问题了,与你之前写的基于memcached的session管理工具有关:

http://www.iteye.com/topic/1127470#2377945 

 

1、你的MemcachedManager配置在context.xml中,因此使用的是tomcat 的 org.apache.catalina.loader.StandardClassLoader

2、而Web项目中使用的是WebAppClassLoader

 

1、首先web项目使用WebAppClassLoader加载User 并放到session

2、此时操作session没问题

 

3、更新classes中的类,此时会发生reload  session会序列化出去

4、reload完毕时 session会使用StandardClassLoader反序列化回user 

5、此时session中的user和我们需要的user已经不一样了。。

 

0 请登录后投票
   发表时间:2012-11-26  
前几天我碰到同样的问题,应用场景和基本差不多,不过我是用Memcached做Session复制。
据我使用的经验,Memcached在反序列化同一个JVM对象时是没问题的,如果是跨JVM好像不可以(不知道有哪位大侠可以解决这个问题)。
我是用另一种办法解决的,但这种办法只是针对需要反序列化较少的对象。
我是先将对象转为json字符串(如阿里的fastjson),存入Memcached,然后在客户端将json字符串转为指定对象,就OK了。
供参考,呵呵!
0 请登录后投票
   发表时间:2012-11-26  
googlecode 上有用memcache 替换tomcatsession的组件
Session共享 MSM(Memcache Session Manager)
0 请登录后投票
   发表时间:2012-11-27  
andye 写道
前几天我碰到同样的问题,应用场景和基本差不多,不过我是用Memcached做Session复制。
据我使用的经验,Memcached在反序列化同一个JVM对象时是没问题的,如果是跨JVM好像不可以(不知道有哪位大侠可以解决这个问题)。
我是用另一种办法解决的,但这种办法只是针对需要反序列化较少的对象。
我是先将对象转为json字符串(如阿里的fastjson),存入Memcached,然后在客户端将json字符串转为指定对象,就OK了。
供参考,呵呵!

我使用了Map来保存一些数据,这样就不存在跨JVM了 每个classLoader都有,只要不放自定义对象就OK了
0 请登录后投票
   发表时间:2012-11-27   最后修改:2012-11-27
kidding87 写道
googlecode 上有用memcache 替换tomcatsession的组件
Session共享 MSM(Memcache Session Manager)


这个组件我使用过的, 用的是Spymemcached连接的memcached

我比较喜欢xmemcached java客户端 我们国产的开源项目!

其实我也是模拟的MSM完成的,只不过用xmemcached 用的太好了 比较喜欢
所以就自己照着MSM(MSM1.6源码看了一部分) 做了一个简单的sessionManager 用的xmemcached做的客户端连接
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics