Spring MVC+AOP项目Java反序列化问题:找不到CGLIB增强类
这个问题我之前也碰到过,核心原因是你序列化的不是原始的SampleBean实例,而是Spring通过CGLIB动态生成的代理子类——这类动态生成的类只存在于当前JVM的运行时内存中,不会被打包到项目依赖里,所以反序列化时自然找不到对应的类。下面给你几个具体的排查方向:
确认序列化的对象是否为Spring代理实例
在序列化之前,打印一下对象的getClass().getName(),如果输出包含$$EnhancerBySpringCGLIB$$,那说明你确实在序列化代理对象。你也可以用Spring提供的AopUtils.isAopProxy()方法快速判断对象是否是代理类。排查SampleBean被代理的原因
Spring默认会给以下几种Bean生成CGLIB代理:- 带有
@Transactional、@Cacheable、@Async这类切面注解的类 - 被自定义AOP切面切入的类(比如通过
@Aspect定义的切面) - 配置了
proxy-target-class=true的Spring容器中,所有非接口实现类的Bean
你可以检查SampleBean的代码和Spring配置,看看是不是触发了上述任意一种代理逻辑。
- 带有
修改序列化逻辑,序列化原始对象而非代理
如果你的需求就是要序列化SampleBean本身,而不是代理类,可以用Spring的AopTargetUtils.getTargetObject()方法获取代理背后的真实对象,然后序列化这个真实对象。示例代码:Object realObject = AopTargetUtils.getTargetObject(objectToSerialize); ObjectOutputStream oos = new ObjectOutputStream(outputStream); oos.writeObject(realObject);注意:如果真实对象存在循环引用或者没有实现
Serializable接口,可能需要额外处理。检查序列化与反序列化环境的一致性
如果序列化和反序列化是在不同的JVM进程中进行的,那动态生成的CGLIB代理类肯定无法跨进程复用,这种情况下必须确保序列化的是原始对象。另外,如果两个环境的Spring版本不一致,CGLIB生成的类结构可能有差异,也会导致反序列化失败。排查是否在特殊时机序列化了代理对象
比如在Spring容器初始化过程中、AOP切面的执行逻辑中序列化对象,这时候可能拿到的是还未完全初始化的代理实例?不过这种情况比较少见,更多还是前面几种场景。
内容的提问来源于stack exchange,提问作者javaTest

