Tomcat集群会话复制报错:非序列化属性,如何实现Serializable?
我正尝试在两个Tomcat集群间实现会话复制,同时启用了粘性会话。在web.xml中添加相关配置后运行应用时,出现错误:java.lang.IllegalArgumentException: setAttribute: Non-serializable attribute。查阅Tomcat文档得知,所有会话属性必须实现java.io.Serializable接口。我对此存在疑问:是不是所有通过setAttribute方法存入会话的对象都必须实现该接口?例如以下代码中,sessionObj1是已实现Serializable的String对象,是不是只能存入这类对象?
public class MySession { String sessionObj1 = "Hello"; HttpSession session = request.getSession(); session.setAttribute("New-Session-1", sessionObj1); }
是的,当你在Tomcat集群中启用会话复制时,所有通过setAttribute存入HttpSession的对象必须实现java.io.Serializable接口。
原因很直接:会话复制的核心是把整个会话对象(包括所有属性)序列化,之后才能在集群节点间传输或者持久化。如果会话里的某个属性不支持序列化,Tomcat无法完成复制操作,就会抛出你遇到的非法参数异常。
结合你的代码来看:String类本身默认实现了Serializable接口,所以把sessionObj1存入会话是完全合规的。但如果换成一个自定义的、未实现Serializable的类实例,比如:
public class MyNonSerializableObj { private String name; // 未实现Serializable接口 } // 存入会话会触发错误 session.setAttribute("non-serial-obj", new MyNonSerializableObj());
这种情况就会直接导致你遇到的报错。
另外要注意:哪怕启用了粘性会话,会话复制依然可能在节点故障、会话过期或者负载均衡策略调整时触发,所以所有会话属性都必须满足序列化要求,不能因为粘性会话就忽略这一点。
内容的提问来源于stack exchange,提问作者Ganapathy R

