2013-10-03 62 views
2

编辑Spring Batch的@StepScope不能生成CGLIB子类

我创建的复制问题的测试项目。它可以在https://github.com/tomverelst/test-batch找到。

首先运行maven命令exec:java启动HSQL数据库。然后,您可以运行JUnit测试MigrationJobConfigurationTest加载Spring应用程序上下文。

原来的问题

当开始我的Spring Batch的应用程序,我得到下面的异常当春乃发生加载我的工作的配置:

Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy34]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy34 

这是由@StepScope注释在我工作的配置引起。它试图用CGLIB代理一个已经用JDK代理代理的类,我不知道这个JDK代理来自哪里。

我也尝试过使用@Scope(value = "step", proxyMode = ScopedProxyMode.NO),但是当我调用JDK代理时,我得到了一个堆栈溢出错误,它继续调用它自己。

如果我删除@StepScope批注,应用程序将正常启动,但我需要能够将它们用于我的工作。

Spring配置

<context:component-scan base-package="com.jnj.rn2.batch" /> 

<context:annotation-config /> 

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

<bean class="org.springframework.batch.core.scope.StepScope" /> 

// Job repository etc 
... 

MigrationJobConfiguration

@Configuration 
public class MigrationJobConfiguration { 

    @Autowired 
    private JobBuilderFactory jobs; 

    @Autowired 
    private StepBuilderFactory steps; 

    @Autowired 
    private MigrationService migrationService; 

    @Bean 
    public Job migrationJob() { 
     return jobs.get("migrationJob") 
      .start(migrateCrfStep()) 
      .next(indexRequestsStep()) 
      .build(); 
    } 

    @Bean 
    public Step migrateCrfStep() { 
     return steps.get("migrateCrfStep") 
      .tasklet(migrateCrfTasklet()) 
      .build(); 
    } 

    @Bean 
    public Step indexRequestsStep() { 
     return steps.get("indexRequestsStep") 
      .<LegacyRequest,LegacyRequest> chunk(5) 
      .reader(indexRequestReader()) 
      .processor(indexRequestProcessor()) 
      .writer(indexRequestWriter()) 
      .build(); 
    } 

    @Bean 
    @StepScope 
    public MigrateCrfTasklet migrateCrfTasklet() { 
     return new MigrateCrfTasklet(); 
    } 

    @Bean 
    @StepScope 
    public IndexRequestItemReader indexRequestReader() { 
     return new IndexRequestItemReader(); 
    } 

    @Bean 
    @StepScope 
    public IndexRequestItemProcessor indexRequestProcessor() { 
     return new IndexRequestItemProcessor(); 
    } 

    @Bean 
    @StepScope 
    public IndexRequestItemWriter indexRequestWriter() { 
     return new IndexRequestItemWriter(); 
    } 

    // Setters 
    ... 
} 

回答

4

我不能为你提供一个实际的答案(还),但我已经调试您所提供的例子,这种情况正在发生:

  • @Configuration定义读者看到@StepScope标注其注解为创建并注册为reader读者@Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS)
  • CGLIB子类,而原来的bean被注册为scopedTarget.reader
  • StepScope开始和后期处理step范围的bean。它检测CGLIB扩展reader定义并尝试为其创建代理=>错误

有两种冲突的代理机制。有一些奇怪的事情发生在我看来,这是行不通的。将尝试通过Spring JIRA进行搜索。


UPDATE

找到解决方案 - 你需要disable auto-proxying的步骤范围:

<bean class="org.springframework.batch.core.scope.StepScope"> 
    <property name="autoProxy" value="false" /> 
</bean> 
+1

这适用于我创建的测试项目,但由于某种原因,不在我的主项目中。我现在用'@ EnableBatchProcessing'从XML更改为Java Config,并且它可以工作。 –

+1

@Pavel使用@StepScope时,我们如何设置autoProxy为false?这是在没有XML配置的情况下。 – gsndev

+0

@gsndev如果你没有使用XML配置,你将不会有我的答案中描述的冲突(哪个是OP的问题)。如果您在没有XML配置的情况下得到类似的异常,那么我建议您单独提问。 –

1

伊斯利从您的配置文件中删除<bean class="org.springframework.batch.core.scope.StepScope" />;你不需要添加它明确的,因为是在批量命名空间中定义(如official documentation of Step scope描述)

+0

这导致在同一个例外。 –

+0

这解决了我的症状。弹簧范围规则最好是间接的,但一旦你掌握了它们就有意义。 –