J'utilise la version 2.2.4 de Spring Batch.RELEASE J'ai essayé d'écrire un exemple simple avec les beans StateReader, ItemProcessor et ItemWriter avec état.
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;
}
}
Dans mon test d'intégration, je déclare mes beans dans une classe statique interne Java config comme celle ci-dessous:
@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());
}
}
Ce test réussit.
Mais dès que je définis mon StatefulItemReader comme un bean à portée d'étape (ce qui est mieux pour un lecteur avec état), le code "avant l'étape" n'est plus réalisé.
...
@Bean
@StepScope
public ItemReader<String> reader() {
return new StatefulItemReader();
}
...
Et je remarque le même problème avec le processeur et mes beans d'écriture.
Qu'est ce qui ne va pas avec mon code? Est-ce lié à ce problème résolu: https://jira.springsource.org/browse/BATCH-12
Tout mon projet Maven avec plusieurs tests JUnit peut être trouvé sur GitHub: https://github.com/galak75/spring-batch-step-scope
Merci d'avance pour vos réponses.
Lorsque vous configurez un bean comme suit:
@Bean
@StepScope
public MyInterface myBean() {
return new MyInterfaceImpl();
}
Vous dites à Spring d'utiliser le mode proxy ScopedProxyMode.TARGET_CLASS
. Cependant, en renvoyant le MyInterface
, au lieu du MyInterfaceImpl
, le proxy n'a de visibilité que sur les méthodes du MyInterface
. Cela empêche Spring Batch de trouver les méthodes sur MyInterfaceImpl
qui ont été annotées avec les annotations d'écoute comme @BeforeStep
. La bonne façon de configurer ceci est de retourner MyInterfaceImpl
sur votre méthode de configuration comme ci-dessous:
@Bean
@StepScope
public MyInterfaceImpl myBean() {
return new MyInterfaceImpl();
}
Nous avons ajouté un message de journal d'avertissement au démarrage qui souligne, lorsque nous recherchons les méthodes d'écoute annotées, si l'objet est mandaté et que la cible est une interface, nous ne pourrons pas trouver de méthodes sur la classe d'implémentation avec des annotations sur leur.