【问题标题】:Spring Batch @StepScope cannot generate CGLIB subclassSpring Batch @StepScope 无法生成 CGLIB 子类
【发布时间】:2013-10-03 12:39:30
【问题描述】:

编辑

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

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

原始问题

在启动我的 Spring Batch 应用程序时,当 Spring 加载我的作业配置时出现以下异常:

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 注释,应用程序将正确启动,但我需要能够将它们用于我的工作。

弹簧配置

<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
    ...
}

【问题讨论】:

    标签: java spring spring-batch spring-aop cglib


    【解决方案1】:

    我无法(目前)为您提供实际答案,但是我已经调试了您提供的示例,并且正在发生这种情况:

    • @Configuration 定义阅读器看到 @StepScope 注释,该注释用 @Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS) 注释
    • 读取器的CGLIB子类创建并注册为reader,而原始bean注册为scopedTarget.reader
    • StepScope 启动并后处理 step 范围 bean。它检测到 CGLIB 扩展 reader 定义并尝试为该定义创建代理 => ERROR

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


    更新

    找到解决方案 - 您需要 disable auto-proxying 获取步骤范围:

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

    【讨论】:

    • 这在我创建的测试项目中有效,但由于某种原因还没有在我的主项目中。我现在使用 @EnableBatchProcessing 从 XML 更改为 Java Config,它可以工作了。
    • @Pavel 在使用@StepScope 时如何将 autoProxy 设置为 false?这是在没有 XML 配置的情况下。
    • @gsndev 如果您不使用 XML 配置,您将不会遇到我的回答中描述的冲突(这是 OP 的问题)。如果您在没有 XML 配置的情况下遇到类似的异常,那么我建议您提出单独的问题。
    【解决方案2】:

    从您的配置文件中轻松删除&lt;bean class="org.springframework.batch.core.scope.StepScope" /&gt;;您不需要显式添加它,因为它是在批处理命名空间中定义的(如official documentation of Step scope 中所述)

    【讨论】:

    • 这会导致同样的异常。
    • 这解决了我的症状。 Spring 范围规则充其量是间接的,但一旦掌握它们就会有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 2012-05-09
    • 2022-10-13
    • 1970-01-01
    • 2016-04-17
    • 2020-09-21
    相关资源
    最近更新 更多