You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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来处理基本类型的加载问题:

  1. 编写自定义的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);
        }
    }
}
  1. 让JSF使用这个自定义流:你可以扩展JSF的ApplicationObjectInputStream,或者自定义ResponseStateManager来替换默认的反序列化逻辑,确保视图状态反序列化时用你写的这个流。

方案3:自定义Tomcat JDBC会话的序列化器

Tomcat的JDBC会话存储支持自定义序列化器,你可以配置一个能处理Spring AOP代理和基本类型的序列化器:

  • 在Tomcat的context.xml中,给Manager元素添加serializer属性,指定自定义序列化器的全类名,这个类需要实现org.apache.catalina.util.CustomObjectInputStreamFactory接口,返回你自定义的ObjectInputStream实例。

验证步骤

  1. 先尝试方案1:移除代理注解,检查所有会话Bean的可序列化性,测试页面跳转和命令链接,看Restore View阶段是否正常
  2. 如果必须用代理,再尝试方案2或3,部署后验证ClassNotFoundException: int是否消失

内容的提问来源于stack exchange,提问作者Mohammed Javad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:44:21