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

Spring Boot 1.5升级至2.0时Ehcache抛出NotSerializableException问题

问题分析与解决方案

核心原因

你遇到的java.io.NotSerializableException: org.springframework.integration.support.MessageBuilder异常,本质是Ehcache在开启copyOnRead或copyOnWrite时,要求缓存对象必须实现Serializable接口,而MessageBuilder本身并没有实现该接口。

在Spring Boot 1.5中,HTTP网关的handler返回的是已构建完成的GenericMessage(它实现了Serializable),所以缓存逻辑正常;但升级到Spring Boot 2.0后,你的通知链顺序和处理逻辑出现了问题:缓存拦截器提前拦截了目标方法的返回值——也就是未完成构建的MessageBuilder,而非经过转换后的可序列化GenericMessage。

看你的XML通知链配置:

<int-http:request-handler-advice-chain>
    <ref bean="genericXMLMessageAdvice" />
    <ref bean="cacheAdvice" />
</int-http:request-handler-advice-chain>

Spring Integration的通知链执行顺序是先执行链中靠前的advice,再通过invocation.proceed()调用后续逻辑。这意味着cacheAdvice会先拦截目标方法的返回值(此时是MessageBuilder),而genericXMLMessageAdvice的转换逻辑还未执行,最终导致不可序列化的MessageBuilder被存入缓存。

解决方案

方案1:调整通知链顺序(推荐)

把cacheAdvice放在genericXMLMessageAdvice之前,确保缓存拦截器处理的是经过转换后的GenericMessage:

<int-http:request-handler-advice-chain>
    <ref bean="cacheAdvice" />
    <ref bean="genericXMLMessageAdvice" />
</int-http:request-handler-advice-chain>

调整后,执行流程变为:

  1. cacheAdvice启动拦截
  2. 调用invocation.proceed()进入genericXMLMessageAdvice
  3. genericXMLMessageAdvice将目标方法返回的MessageBuilder转换为GenericMessage
  4. cacheAdvice拿到可序列化的GenericMessage并完成缓存

方案2:直接在缓存拦截器中完成转换

如果不想调整通知链顺序,可以修改cacheAdvice的逻辑,在缓存前手动将MessageBuilder转换为GenericMessage:

@Bean
public MethodInterceptor cacheAdvice() {
    CacheInterceptor interceptor = createGatewayInterceptor(TWENTY_FOUR_HOUR_CACHE);
    // 包装原有拦截逻辑,先转换再缓存
    return invocation -> {
        Object result = invocation.proceed();
        // 处理MessageBuilder,转换为可序列化的GenericMessage
        if (result instanceof MessageBuilder) {
            result = ((MessageBuilder<?>) result).build();
        }
        // 调用原有缓存逻辑
        MethodInvocation proxyInvocation = new MethodInvocation() {
            @Override
            public Object proceed() throws Throwable {
                return result;
            }
            // 实现其他MethodInvocation方法,复用原有参数和方法信息
            @Override
            public Object getThis() { return invocation.getThis(); }
            @Override
            public Method getMethod() { return invocation.getMethod(); }
            @Override
            public Object[] getArguments() { return invocation.getArguments(); }
        };
        return interceptor.invoke(proxyInvocation);
    };
}

方案3:关闭Ehcache的copyOnRead/copyOnWrite(不推荐)

如果不需要Ehcache的复制保证功能,可以修改Ehcache配置文件,移除copyOnRead和copyOnWrite属性。但此方案会牺牲缓存数据的线程安全性和一致性,仅作为临时应急方案。

验证

修改后重启应用,通过断点或日志确认缓存的对象类型为GenericMessage,此时NotSerializableException应该会消失,缓存逻辑恢复正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:37:39