Spring-batch @BeforeStep does not work with @StepScope

匿名 (未验证) 提交于 2019-12-03 01:12:01

问题:

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

public class StatefulItemReader implements ItemReader {      private List 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() 

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

@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")                     .chunk(1)                     .reader(reader())                     .processor(processor())                     .writer(writer())                     .build();         }          @Bean         public ItemReader reader() {             return new StatefulItemReader();         }          @Bean         public ItemProcessor processor() {             return new StatefulItemProcessor();         }          @Bean         public ItemWriter 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 StatefulItemReader as a step scoped bean (which is better for a stateful reader), the "before step" code is no longer executed.

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

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

What's wrong with my code? Is it related to this resolved issue: 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

Thank you in advance for your answers.

回答1:

When you configure a bean as follows:

@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 MyInterfaceImpl that have been annotated with the listener annotations like @BeforeStep. The correct way to configure this is to return MyInterfaceImpl on your configuration method like below:

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



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!