0

我有一个使用 Spring 4.3.24 用 Ja​​va8 编写的 JEE 应用程序。由于我的应用程序的前端使用的是 JSF 2.x,因此我还使用自定义 spring 范围 - 由第三方库提供的对话访问,即 1.4 版中的 myfaces-orchestra

由于 Selenium 测试广泛涵盖了该应用程序,因此我目前正在分析在多个线程中运行测试的主题。详细说明:一个托管应用服务器的 JVM——在我的例子中是 WebSphere 8.5.5,另一个使用 JUnit 4.10 的 JVM 在多个线程中运行 selenium 测试。

我面临的问题,但仅在并行运行测试时,在尝试与对话访问 bean 交互时偶尔会 ClassCastException从 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 是不同的)

我已经排除的是:

  1. 这不是与底层 bean 的初始化相关的问题。尽管 bean 有一个 PostConstruct,但它已成功初始化
  2. 我认为这个问题是升级到 spring 4.x(从 3.x)引起的,所以我尝试禁用 Objenesis(通过将 spring.objenesis.ignore 设置为“true”),但这也没有帮助
4

1 回答 1

0

经过进一步调查,我认为我找到了问题的根本原因 - 它位于 Orchestra 实施中

基本上,Orchestra 每次实例化会话访问 bean 时,都会操纵 bean 定义属性——它试图设置

AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE=Boolean.TRUE

据我了解,此设置告诉 AOP 创建 bean 的 CGLIB 代理。由于 bean 定义中的 bean 属性保存在标准 HashMap 中,因此这种方法会导致竞争条件,后来最终导致对话访问 bean 的双重代理

于 2021-05-10T06:14:44.563 回答