web-dev-qa-db-ja.com

Spring-batch @BeforeStepは@StepScopeでは機能しません

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

私の統合テストでは、次のような内部静的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());
    }
}

このテストは合格です。

しかし、StatefulItemReaderをステップスコープBean(ステートフルリーダーに適しています)として定義するとすぐに、「前のステップ」コードはもうありません。実行されました。

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

また、プロセッサーとライターBeanでも同じ問題が発生します。

私のコードの何が問題になっていますか?これはこの解決された問題に関連していますか: https://jira.springsource.org/browse/BATCH-12

いくつかのJUnitテストを含む私のMavenプロジェクト全体は、GitHubで見つけることができます: https://github.com/galak75/spring-batch-step-scope

ご回答ありがとうございます。

26
Géraud

次のようにBeanを構成する場合:

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

SpringにプロキシモードScopedProxyMode.TARGET_CLASSを使用するように指示しています。ただし、MyInterfaceの代わりにMyInterfaceImplを返すことにより、プロキシはMyInterfaceのメソッドのみを表示できます。これにより、Spring Batchは@BeforeStepなどのリスナーアノテーションが付けられたMyInterfaceImplのメソッドを見つけることができなくなります。これを構成する正しい方法は、以下のような構成メソッドでMyInterfaceImplを返すことです。

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

起動時に警告ログメッセージを追加しました。これは、注釈付きリスナーメソッドを探しているため、オブジェクトがプロキシ化されていて、ターゲットがインターフェイスである場合、実装クラスで注釈が付いているメソッドを見つけることができません。それら。

38
Michael Minella