Java Spring-batch @BeforeStep 不适用于 @StepScope

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21241683/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:35:11  来源:igfitidea点击:

Spring-batch @BeforeStep does not work with @StepScope

javaspringspring-batch

提问by Géraud

I'm using Spring Batch version 2.2.4.RELEASE I tried to write a simple example with stateful ItemReader, ItemProcessor and ItemWriter beans.

我正在使用 Spring Batch 版本 2.2.4.RELEASE 我试图用有状态的 ItemReader、ItemProcessor 和 ItemWriter bean 编写一个简单的例子。

public class StatefulItemReader implements ItemReader<String> {

    private List<String> list;

    @BeforeStep
    public void initializeState(StepExecution stepExecution) {
        this.list = new ArrayList<>();
    }

    @AfterStep
    public ExitStatus exploitState(StepExecution stepExecution) {
        System.out.println("******************************");
        System.out.println(" READING RESULTS : " + list.size());

        return stepExecution.getExitStatus();
    }

    @Override
    public String read() throws Exception {
        this.list.add("some stateful reading information");
        if (list.size() < 10) {
            return "value " + list.size();
        }
        return null;
    }
}

In my integration test, I'm declaring my beans in an inner static java config class like the one below:

在我的集成测试中,我在内部静态 java 配置类中声明了我的 bean,如下所示:

@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class SingletonScopedTest {

    @Configuration
    @EnableBatchProcessing
    static class TestConfig {
        @Autowired
        private JobBuilderFactory jobBuilder;
        @Autowired
        private StepBuilderFactory stepBuilder;

        @Bean
        JobLauncherTestUtils jobLauncherTestUtils() {
            return new JobLauncherTestUtils();
        }

        @Bean
        public DataSource dataSource() {
            EmbeddedDatabaseBuilder embeddedDatabaseBuilder = new EmbeddedDatabaseBuilder();
            return embeddedDatabaseBuilder.addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql")
                    .addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql")
                    .setType(EmbeddedDatabaseType.HSQL)
                    .build();
        }

        @Bean
        public Job jobUnderTest() {
            return jobBuilder.get("job-under-test")
                    .start(stepUnderTest())
                    .build();
        }

        @Bean
        public Step stepUnderTest() {
            return stepBuilder.get("step-under-test")
                    .<String, String>chunk(1)
                    .reader(reader())
                    .processor(processor())
                    .writer(writer())
                    .build();
        }

        @Bean
        public ItemReader<String> reader() {
            return new StatefulItemReader();
        }

        @Bean
        public ItemProcessor<String, String> processor() {
            return new StatefulItemProcessor();
        }

        @Bean
        public ItemWriter<String> writer() {
            return new StatefulItemWriter();
        }
    }

    @Autowired
    JobLauncherTestUtils jobLauncherTestUtils;

    @Test
    public void testStepExecution() {
        JobExecution jobExecution = jobLauncherTestUtils.launchStep("step-under-test");

        assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
    }
}

This test passes.

此测试通过。

But as soon as I define my StatefulItemReaderas a step scoped bean (which is better for a stateful reader), the "before step" code is no longer executed.

但是一旦我将StatefulItemReader定义为 step 范围的 bean(这对有状态的读者来说更好),“before step”代码就不再执行。

...
    @Bean
    @StepScope
    public ItemReader<String> reader() {
        return new StatefulItemReader();
    }
...

And I notice the same issue with processor and my writer beans.

我注意到处理器和我的编写器 bean 也存在同样的问题。

What's wrong with my code? Is it related to this resolved issue: https://jira.springsource.org/browse/BATCH-1230

我的代码有什么问题?是否与这个已解决的问题有关:https: //jira.springsource.org/browse/BATCH-1230

My whole Maven project with several JUnit tests can be found on GitHub: https://github.com/galak75/spring-batch-step-scope

我的整个 Maven 项目和几个 JUnit 测试可以在 GitHub 上找到:https: //github.com/galak75/spring-batch-step-scope

Thank you in advance for your answers.

预先感谢您的回答。

采纳答案by Michael Minella

When you configure a bean as follows:

当您按如下方式配置 bean 时:

@Bean
@StepScope
public MyInterface myBean() {
    return new MyInterfaceImpl();
}

You are telling Spring to use the proxy mode ScopedProxyMode.TARGET_CLASS. However, by returning the MyInterface, instead of the MyInterfaceImpl, the proxy only has visibility into the methods on the MyInterface. This prevents Spring Batch from being able to find the methods on MyInterfaceImplthat have been annotated with the listener annotations like @BeforeStep. The correct way to configure this is to return MyInterfaceImplon your configuration method like below:

您是在告诉 Spring 使用代理模式ScopedProxyMode.TARGET_CLASS。但是,通过返回MyInterface,而不是MyInterfaceImpl,代理只能查看 上的方法MyInterface。这可以防止 Spring Batch 找到MyInterfaceImpl已使用侦听器注释(如@BeforeStep. 配置它的正确方法是返回MyInterfaceImpl您的配置方法,如下所示:

@Bean
@StepScope
public MyInterfaceImpl myBean() {
    return new MyInterfaceImpl();
}

We have added a warning log message on startup that points out, as we look for the annotated listener methods, if the object is proxied and the target is an interface, we won't be able to find methods on the implementing class with annotations on them.

我们在启动时添加了一条警告日志消息,指出当我们寻找带注释的侦听器方法时,如果对象是代理的并且目标是接口,我们将无法在带有注释的实现类上找到方法他们。