如何解决使用会话访问类型的 Spring 代理 bean 时出现随机 ClassCastException
我有一个用 Java8 编写的 JEE 应用程序,它使用 Spring 4.3.24。由于我的应用程序的前端使用的是 JSF 2.x,我还使用了自定义 spring 范围 - 第三方库提供的对话访问,即 1.4 版中的 myfaces-orchestra
由于应用程序被 Selenium 测试广泛覆盖,我目前正在分析在多线程中运行测试的主题。详细说明:一个托管应用程序服务器的 JVM - 在我的例子中是 WebSphere 8.5.5,一个使用 JUnit 4.10 的 JVM 在多个线程中运行 selenium 测试。
我面临的问题,但仅在并行运行测试时,偶尔 ClassCastException
在尝试与对话访问 bean 交互时被抛出 CGLIB 类。
异常如下所示:
Exception: java.lang.ClassCastException: com.sun.proxy.$Proxy499 incompatible with some.package.PageBackingBean
at some.package.PageBackingBean$$FastClassBySpringCGLIB$$ecd1ff4d.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:671)
如前所述,异常只会不时发生。另外,可以注意到,这通常发生在两个或多个线程在同一毫秒内引用相同类型的会话 bean 的情况下(当然,由于这两个线程使用不同的会话,底层 bean 是不同的)
我已经排除的是:
- 这不是与底层 bean 初始化相关的问题。尽管 bean 具有 PostConstruct,但它已成功初始化
- 我认为这个问题是在升级到 spring 4.x(从 3.x 开始)时提出的,所以我尝试禁用 Objenesis(通过将 spring.objenesis.ignore 设置为“true”),但这也没有帮助
解决方法
经过进一步调查,我想我找到了问题的根本原因 - 它位于 Orchestra 实现中
基本上, Orchestra 每次实例化会话访问 bean 时,都会操纵 bean 定义属性 - 它试图设置
AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE=Boolean.TRUE
据我所知,这个设置告诉 AOP 创建 bean 的 CGLIB 代理。由于 bean 定义中的 bean 属性保存在标准的 HashMap 中,因此这种方法会导致竞争条件,最终导致对话访问 bean 的双重代理
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。