2014-01-20 40 views
15

我使用的是Spring批處理版本2.2.4.RELEASE 我試圖用有狀態的ItemReader,ItemProcessor和ItemWriter bean編寫一個簡單的例子。Spring批處理@BeforeStep不能用@StepScope

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配置類類似下面我豆類:

@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(); 
    } 
... 

而且我注意到處理器和我的編寫器豆的相同問題。

我的代碼有什麼問題?這是否與這個解決問題:https://jira.springsource.org/browse/BATCH-1230

幾個JUnit測試我的整個Maven項目可以在GitHub上找到:https://github.com/galak75/spring-batch-step-scope

預先感謝您爲您的回答。

+0

這可能是一個錯誤。看來代理版本的閱讀器/處理器/寫入器沒有被自動註冊爲StepListener。我在Jira中創建了一個問題來跟蹤它的工作:https://jira.springsource.org/browse/BATCH-2169 –

+0

@Géraud,我添加了另一個在Singleton範圍內執行CompositeItemProcessor場景的測試,它也失敗了。我已經向GitHub發送了一個拉取請求。我會爲此添加或修改Jira。 – hoserdude

+0

@hoserdude,對不起,我這些時間都非常忙碌......我會盡快接受您的拉客請求 –

回答

26

當你配置一個bean如下:

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

你告訴Spring使用代理模式ScopedProxyMode.TARGET_CLASS。但是,通過返回MyInterface而不是MyInterfaceImpl,代理只能看到MyInterface上的方法。這可以防止Spring Batch能夠找到MyInterfaceImpl上已使用諸如@BeforeStep之類的偵聽器註釋進行註釋的方法。配置的正確方法是將您的配置方法,返回MyInterfaceImpl象下面這樣:

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

我們增加所指出的,當我們尋找的註解監聽方法,如果對象是在啓動時的警告日誌消息代理和目標是一個接口,我們將無法找到具有註釋的實現類的方法。

+0

謝謝你的幫助邁克爾!順便說一句,這就是我正要測試的! (我們遇到了後期綁定值的問題,我們以同樣的方式解決了這個問題)。 它讓我想到了應該在Java配置文件中聲明bean的方式:通常,在聲明語句中使用接口是一種很好的做法;但是java配置是一個特殊的類,我們在其中選擇要使用的實現。因此,聲明實際返回的實現可能是一個好習慣(在使用XML配置時,順便說一句,我們只給出實際的實現類...) 你同意嗎? –

+0

我確實認爲返回類而不是接口可以在java配置中有意義。我不會說這應該是一個硬性規則,但除非你很好地掌握代理如何在引擎蓋下工作,否則它會爲你節省一些頭痛。我在啓動時爲您遇到的情況添加了警告消息,以防止未來的用戶遇到同樣的問題。我希望這有助於! –

+0

沒錯。再次感謝你的幫助!我在使用彈簧批量發佈時看到了這個警告2.2.5 –