【问题标题】:Spring @Autowired fails in case of Cobertura instrumented class在 Cobertura 检测类的情况下,Spring @Autowired 失败
【发布时间】:2012-10-16 07:39:18
【问题描述】:

问题

Cobertura 仪器在特定情况下会破坏自动装配的弹簧。有谁知道如何解决这个问题?

场景

  • 我正在运行带有 cobertura-maven-plugin 版本 2.5.1 的 MVN 3.0.4。
  • mvn 测试运行没有问题
  • mvn compile、package 等也可以正常运行。
  • mvn cobertura:cobertura 也运行没有任何问题,直到添加了 2 个引入许多新类的新功能,包括两个新的 com.mycompany.executor 执行器类。 (示例:除了现有的 MyExecutor 之外,还添加了 MyHappyExecutor 和 MySadExecutor)
  • 从 cobertura 检测过程中排除 MyExecutor 似乎可以修复自动装配
  • 检查 spring 自动装配输出确认正确的 bean 正在自动装配。

故障点

尝试在 myService 中自动装配 myExecutor 的检测版本时,自动装配失败。这在添加 MyHappyExecutor 和 MySadExecutor 之前运行良好。 MyHappyExecutor 和 MySadExecutor 是自动装配的,并且只在 MyExecutor 中使用。

我在下面附上了异常输出。请注意类名和包名已被编辑。

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myService': Injection of autowired dependencies failed; 
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mycompany.executor.MyExecutor com.mycompany.service.impl.MyServiceImpl.myExecutor; 
nested exception is java.lang.IllegalArgumentException: Can not set com.mycompany.executor.MyExecutor field com.mycompany.service.impl.MyServiceImpl.myExecutor to $Proxy20

结论

Cobertura 检测过程中的某些东西弄乱了 Springs 的自动装配。

更新 1

强制 CGLIB 类代理会将错误类型更改为“java.lang.NoClassDefFoundError”错误。这会影响标准测试目标以及 Cobertura 目标。

<aop:config proxy-target-class="true"/>

更新 2

这是 3 个有问题的类的 springs 启动过程的输出。

2012-11-01 16:21:51 INFO  [main] Overriding bean definition for bean 'myExecutor': replacing [Generic bean: class [com.mycompany.executor.MyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.MyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)
2012-11-01 16:21:51 INFO  [main] Overriding bean definition for bean 'happyExecutor': replacing [Generic bean: class [com.mycompany.executor.HappyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.HappyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)
2012-11-01 16:21:51 INFO  [main] Overriding bean definition for bean 'sadExecutor': replacing [Generic bean: class [com.mycompany.executor.SadExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.SadExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)

【问题讨论】:

标签: spring maven instrumentation autowired cobertura


【解决方案1】:

另一种选择是让执行器实现一个接口(比如说执行器)并在 MyService 中使用接口注入。 Spring 将知道如何构建代理以实现接口。 大多数时候我更喜欢这种方法而不是 proxyTargetClass。

【讨论】:

    【解决方案2】:

    对于您的测试,您需要设置proxyTargetClass=true

    @EnableTransactionManagement(mode=AdviceMode.ASPECTJ, proxyTargetClass=true)
    

    如果这适用于您的测试,但是当您运行您的应用程序时它失败了,那么您需要为测试和您的应用程序单独配置。测试配置集proxyTargetClass=true 和应用配置集proxyTargetClass=false

    对于您的NoClassDefFoundError 错误,我们需要查看堆栈跟踪。你可能没有包含 spring-aop 库

    【讨论】:

      【解决方案3】:

      我们遇到了关于 Aspect 和包私有类的类似问题。 我们的修复非常简单,因为我们可以将我们的包私有类公开。

      在那之后,由于 cobertura 出现了更多问题,我们搬到了 JaCoCo,并且对结果非常满意。默认情况下,使用 cobertura 构建的 maven 构建是这样配置的:

      • 运行测试
      • 通过 cobertura 检测代码
      • 再次运行测试并测量覆盖率

      由于 JaCoCo 使用代理而不是字节码工具来测量代码覆盖率,因此测试只运行一次,从而加快了构建速度。

      如果您需要有关设置 JaCoCo 的更多信息,请参阅 this link

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-30
        • 2019-04-17
        • 2019-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多