Tomcat JDBC会话存储下JSF视图恢复阶段int类加载异常求助
解决Tomcat JDBC会话存储下JSF Restore View阶段的序列化与类加载问题
我来帮你梳理这个问题的根源和可行的解决方案——你遇到的情况其实是Tomcat JDBC会话存储的序列化要求和Spring AOP代理的序列化逻辑冲突导致的,咱们一步步拆解:
问题复盘
你当前的场景和遇到的问题:
- 用Tomcat JDBC会话存储把会话数据放到JVM外部,结果每次点击命令链接时,JSF的Restore View阶段都会抛出严重异常,日志仅给出模糊提示:
com.sun.faces.lifecycle.Phase doPhase SEVERE: JSF1054: (Phase ID: RESTORE_VIEW 1, View ID: ) Exception thrown during phase execution: javax.faces.event.PhaseEvent[source=com.sun.faces.lifecycle.LifecycleImpl@6b18a6e1] - 尝试在
web.xml中设置enableRestoreView11Compatibility=true,但无效果,且这并非根治问题的合理方案 - 给后台Bean添加
@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)注解后,多数页面的问题得到解决,但又出现新的类加载异常:java.lang.ClassNotFoundException: int,且该异常仍伴随Restore View阶段执行异常
根本原因
Tomcat的JDBC会话存储要求会话中的所有对象必须完全可序列化,而你添加的Spring ScopedProxy会生成AOP代理对象。当这些代理对象被序列化存储到JDBC会话中,反序列化时会触发冲突:
Spring的AspectJExpressionPointcut在序列化时会保存切点的相关元数据,其中包含了基本类型(比如int)的描述。但JSF的ApplicationObjectInputStream在反序列化时,会调用Class.forName("int")试图加载这个“类”——可int是Java基本类型,并非一个类,自然会抛出ClassNotFoundException。
可行的解决方案
方案1:移除AOP代理,确保会话Bean完全可序列化(优先推荐)
如果你的会话作用域Bean不需要AOP代理(比如没有用到@Transactional、AspectJ切面这类需要代理的注解),完全可以移除@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS),转而从根本上解决序列化问题:
- 检查所有会话作用域的Bean,以及它们依赖的所有对象,确保都实现了
java.io.Serializable接口 - 对于那些无法序列化的依赖(比如
EntityManager、DataSource这类容器级对象),用transient关键字标记,或者通过Spring的方法注入、@PostConstruct等方式,在反序列化后重新初始化这些依赖
方案2:自定义反序列化逻辑处理基本类型
如果必须保留AOP代理,可以通过自定义ObjectInputStream来处理基本类型的加载问题:
- 编写自定义的
ObjectInputStream,重写resolveClass方法,识别基本类型:
public class CustomJSFObjectInputStream extends ObjectInputStream { public CustomJSFObjectInputStream(InputStream in) throws IOException { super(in); } @Override protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String className = desc.getName(); // 处理所有Java基本类型 switch(className) { case "int": return int.class; case "long": return long.class; case "boolean": return boolean.class; case "byte": return byte.class; case "short": return short.class; case "char": return char.class; case "float": return float.class; case "double": return double.class; default: return super.resolveClass(desc); } } }
- 让JSF使用这个自定义流:你可以扩展JSF的
ApplicationObjectInputStream,或者自定义ResponseStateManager来替换默认的反序列化逻辑,确保视图状态反序列化时用你写的这个流。
方案3:自定义Tomcat JDBC会话的序列化器
Tomcat的JDBC会话存储支持自定义序列化器,你可以配置一个能处理Spring AOP代理和基本类型的序列化器:
- 在Tomcat的
context.xml中,给Manager元素添加serializer属性,指定自定义序列化器的全类名,这个类需要实现org.apache.catalina.util.CustomObjectInputStreamFactory接口,返回你自定义的ObjectInputStream实例。
验证步骤
- 先尝试方案1:移除代理注解,检查所有会话Bean的可序列化性,测试页面跳转和命令链接,看Restore View阶段是否正常
- 如果必须用代理,再尝试方案2或3,部署后验证
ClassNotFoundException: int是否消失
内容的提问来源于stack exchange,提问作者Mohammed Javad
相关产品推荐
相关产品推荐

