获取Spring错误“Bean命名为'x'必须是[y]类型,但实际上是Jenkins类型[$ Proxy]”

时间:2011-12-05 21:12:42

标签: spring unit-testing junit hudson jenkins

我现在已经调试了一段时间了,我希望有人能在这里说清楚。

我使用JDK 1.6将一个Maven项目添加到Jenkins中。我在这个项目中使用AOP来处理数据库事务。

当我在Jenkins中运行构建时,我的测试用例失败,但有以下例外: -

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'dataHandlerClassificationImpl': 
Injection of resource dependencies failed; nested exception is 
org.springframework.beans.factory.BeanNotOfRequiredTypeException: 
Bean named 'writerDataLocationImpl' must be of type [xxx.script.WriterData], 
but was actually of type [$Proxy17]
    ...
    ...
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: 
Bean named 'writerDataLocationImpl' must be of type [xxx.script.WriterData], 
but was actually of type [$Proxy17]
    ...
    ...

DataHandlerClassificationImpl类看起来像这样: -

@Service
public class DataHandlerClassificationImpl extends DataHandler {

    @Resource(name="writerDataLocationImpl")
    private WriterData writerData;

    ...
}       

WriterData是一个包含多个实现的接口。

我可以从IDE中无问题地执行代码。为了确定它是Maven问题还是Jenkins问题,我使用命令行导航到Jenkins的项目作业文件夹,我能够运行mvn test而没有任何错误。

我知道代理错误与AOP有关,而且我只能自动连接到一个接口而不是一个具体的类......但事实并非如此,因为我能够在Jenkins之外运行我的代码

有什么想法吗?谢谢。

2 个答案:

答案 0 :(得分:43)

摘自上述问题评论:

你在Jenkins上运行Cobertura,Sonar或其他代码工具吗?请注意,mvn site也可能配置为在生成的site中包含Cobertura报告。

Cobertura的问题在于它执行相当繁重的字节码检测,包括添加一些自定义接口。当Spring启动时,它会为bean生成代理。如果bean至少有一个接口,则它使用标准Java代理。否则它会尝试创建基于类的代理。

我想在你的情况下使用了CGLIB类代理,但在Cobertura工具之后,Spring回归到java代理。这导致启动错误,因为依赖注入期望类(或CGLIB子类)。

长话短说,强迫CGLIB类代理,你会没事的:

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

答案 1 :(得分:0)

使用AspectJ解决了相同的问题。

有一个豆子

@Configuration public class MyConfig{

@Value("classpath:some.properties")
private Resource theResource;

@Bean
public  SomeResource getSomeResource()
{
    return  SomeResource.getOne(theResource);
}
/******/
 
  @Component
public class SomeResource{
   public SomeResource(Resource r) {...}
   public static getOne(Resource r} { return new SomeResource(r); }

在启用AOP / AspectJ之前,它可以正常工作。该注入可验证SomeResource Bean来自SomeResource类,但是由于它是Proxy,因此会崩溃。

解决方案:对那个Bean使用GLIBC代理而不是AspectJ代理。

@EnableAspectJAutoProxy(proxyTargetClass=false)
public class SomeResource{...}

毫无意义,但现在得到了更清晰的信息

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils
 (file:/path/spring-core/5.2.10.RELEASE/spring-core-5.2.10.RELEASE.jar) to method
java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils

Java意味着无法对此方法进行反思。Spring或Java都需要对此进行修复。