精华帖 (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 有什么区别? 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间: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、禁用热部署,改后重启 |
|
返回顶楼 | |
发表时间:2012-11-23
如果UserInfo实现序列化接口会不会有问题?
|
|
返回顶楼 | |
发表时间:2012-11-23
luciferdevil 写道 如果UserInfo实现序列化接口会不会有问题?
肯定都是实现了序列化接口的撒! 问题不是这里,现在说的是 classLoader 单独重新加载项目应用和重启tomcat服务器会导致不一样,由于热发布项目只是重新加载了当前项目的程序,而整个tomcat容器级别的仍然保存的是之前没发布项目时的classLoader,老得classLoader没有新的Class所以被判断为了2个不同的对象.导致不能加载新Class时出现类型转换错误. 我还在研究中,不过估计问题就在这里了,重启tomcat是对的 因为整个又把每个项目又加载了一次 |
|
返回顶楼 | |
发表时间:2012-11-23
序列话对象不要加@SuppressWarnings("serial")注释,加上private static final long serialVersionUID = -1L;或者其他数字规定序列ID,保证每个tomcat里面的同一个对象序列ID一样就没问题了。eclipse可以自动生成的。
|
|
返回顶楼 | |
发表时间: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已经不一样了。。
|
|
返回顶楼 | |
发表时间:2012-11-26
前几天我碰到同样的问题,应用场景和基本差不多,不过我是用Memcached做Session复制。
据我使用的经验,Memcached在反序列化同一个JVM对象时是没问题的,如果是跨JVM好像不可以(不知道有哪位大侠可以解决这个问题)。 我是用另一种办法解决的,但这种办法只是针对需要反序列化较少的对象。 我是先将对象转为json字符串(如阿里的fastjson),存入Memcached,然后在客户端将json字符串转为指定对象,就OK了。 供参考,呵呵! |
|
返回顶楼 | |
发表时间:2012-11-26
googlecode 上有用memcache 替换tomcatsession的组件
Session共享 MSM(Memcache Session Manager) |
|
返回顶楼 | |
发表时间:2012-11-27
andye 写道 前几天我碰到同样的问题,应用场景和基本差不多,不过我是用Memcached做Session复制。
据我使用的经验,Memcached在反序列化同一个JVM对象时是没问题的,如果是跨JVM好像不可以(不知道有哪位大侠可以解决这个问题)。 我是用另一种办法解决的,但这种办法只是针对需要反序列化较少的对象。 我是先将对象转为json字符串(如阿里的fastjson),存入Memcached,然后在客户端将json字符串转为指定对象,就OK了。 供参考,呵呵! 我使用了Map来保存一些数据,这样就不存在跨JVM了 每个classLoader都有,只要不放自定义对象就OK了 |
|
返回顶楼 | |
发表时间: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做的客户端连接 |
|
返回顶楼 | |