2016-08-15 32 views
0

所以我在彈簧批3.0.7.RELEASE和春季4.3.2.RELEASE有一個問題,其中Listeners沒有在我的ItemProcessor類中運行。如下所示,在@StepScope級別的定期注入正在爲@Value("#{jobExecutionContext['" + Constants.SECURITY_TOKEN + "']}")工作。但它不適用於beforeProcessbeforeStep,我已經嘗試了註釋版本和接口版本。我幾乎100%肯定這在某個時刻起作用,但不知道爲什麼它停止。春季批處理器沒有運行ItemProcessorListener

任何想法?它看起來像我配置錯了嗎?

AppBatchConfiguration.java

@Configuration 
@EnableBatchProcessing 
@ComponentScan(basePackages = "our.org.base") 
public class AppBatchConfiguration { 

    private final static SimpleLogger LOGGER = SimpleLogger.getInstance(AppBatchConfiguration.class); 

    private final static String OUTPUT_XML_FILE_PATH_PLACEHOLDER = null; 
    private final static String INPUT_XML_FILE_PATH_PLACEHOLDER = null; 

    @Autowired 
    public JobBuilderFactory jobBuilderFactory; 

    @Autowired 
    public StepBuilderFactory stepBuilderFactory; 

    @Bean(name = "cimAppXmlReader") 
    @StepScope 
    public <T> ItemStreamReader<T> appXmlReader(@Value("#{jobParameters[inputXmlFilePath]}") 
    String inputXmlFilePath) { 
     LOGGER.info("Job Parameter => App XML File Path :" + inputXmlFilePath); 
     StaxEventItemReader<T> reader = new StaxEventItemReader<T>(); 
     reader.setResource(new FileSystemResource(inputXmlFilePath)); 
     reader.setUnmarshaller(mecaUnMarshaller()); 
     reader.setFragmentRootElementNames(getAppRootElementNames()); 
     reader.setSaveState(false); 

     // Make the StaxEventItemReader thread-safe 
     SynchronizedItemStreamReader<T> synchronizedItemStreamReader = new SynchronizedItemStreamReader<T>(); 
     synchronizedItemStreamReader.setDelegate(reader); 

     return synchronizedItemStreamReader; 
    } 

    @Bean 
    @StepScope 
    public ItemStreamReader<JAXBElement<AppIBTransactionHeaderType>> appXmlTransactionHeaderReader(@Value("#{jobParameters[inputXmlFilePath]}") 
    String inputXmlFilePath) { 
     LOGGER.info("Job Parameter => App XML File Path for Transaction Header :" + inputXmlFilePath); 
     StaxEventItemReader<JAXBElement<AppIBTransactionHeaderType>> reader = new StaxEventItemReader<>(); 
     reader.setResource(new FileSystemResource(inputXmlFilePath)); 
     reader.setUnmarshaller(mecaUnMarshaller()); 

     String[] fragmentRootElementNames = new String[] {"AppIBTransactionHeader"}; 
     reader.setFragmentRootElementNames(fragmentRootElementNames); 
     reader.setSaveState(false); 

     return reader; 
    } 

    @Bean 
    public Unmarshaller mecaUnMarshaller() { 
     Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); 
     marshaller.setPackagesToScan(ObjectFactory.class.getPackage().getName()); 
     return marshaller; 
    } 

    @Bean 
    public Marshaller uberMarshaller() { 
     Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); 
     marshaller.setClassesToBeBound(ServiceRequestType.class); 
     marshaller.setSupportJaxbElementClass(true); 
     return marshaller; 
    } 

    @Bean(destroyMethod="") // To stop multiple close calls, see: http://stackoverflow.com/a/23089536 
    @StepScope 
    public ResourceAwareItemWriterItemStream<JAXBElement<ServiceRequestType>> writer(@Value("#{jobParameters[outputXmlFilePath]}") 
    String outputXmlFilePath) { 
     SyncStaxEventItemWriter<JAXBElement<ServiceRequestType>> writer = new SyncStaxEventItemWriter<JAXBElement<ServiceRequestType>>(); 

     writer.setResource(new FileSystemResource(outputXmlFilePath)); 
     writer.setMarshaller(uberMarshaller()); 
     writer.setSaveState(false); 
     HashMap<String, String> rootElementAttribs = new HashMap<String, String>(); 
     rootElementAttribs.put("xmlns:ns1", "http://some.org/corporate/message/2010/1"); 
     writer.setRootElementAttributes(rootElementAttribs); 
     writer.setRootTagName("ns1:SetOfServiceRequests"); 

     return writer; 
    } 

    @Bean 
    @StepScope 
    public <T> ItemProcessor<T, JAXBElement<ServiceRequestType>> appNotificationProcessor() { 
     return new AppBatchNotificationItemProcessor<T>(); 
    } 

    @Bean 
    public ItemProcessor<JAXBElement<AppIBTransactionHeaderType>, Boolean> appBatchCreationProcessor() { 
     return new AppBatchCreationItemProcessor(); 
    } 


    public String[] getAppRootElementNames() {   
     //get list of App Transaction Element Names   
     return AppProcessorEnum.getValues();   
    } 

    @Bean 
    public Step AppStep() { 
     // INPUT_XML_FILE_PATH_PLACEHOLDER and OUTPUT_XML_FILE_PATH_PLACEHOLDER will be overridden 
     // by injected jobParameters using late binding (StepScope) 
     return stepBuilderFactory.get("AppStep") 
       .<Object, JAXBElement<ServiceRequestType>> chunk(10) 
       .reader(appXmlReader(INPUT_XML_FILE_PATH_PLACEHOLDER)) 
       .processor(appNotificationProcessor()) 
       .writer(writer(OUTPUT_XML_FILE_PATH_PLACEHOLDER)) 
       .taskExecutor(concurrentTaskExecutor()) 
       .throttleLimit(1) 
       .build(); 

    } 

    @Bean 
    public Step BatchCreationStep() { 
     return stepBuilderFactory.get("BatchCreationStep") 
       .<JAXBElement<AppIBTransactionHeaderType>, Boolean>chunk(1) 
       .reader(appXmlTransactionHeaderReader(INPUT_XML_FILE_PATH_PLACEHOLDER)) 
       .processor(appBatchCreationProcessor()) 
       .taskExecutor(concurrentTaskExecutor()) 
       .throttleLimit(1) 
       .build(); 
    } 

    @Bean 
    public Job AppJob() { 
     return jobBuilderFactory.get("AppJob") 
       .incrementer(new RunIdIncrementer()) 
       .listener(AppJobCompletionNotificationListener()) 
       .flow(AppStep()) 
       .next(BatchCreationStep()) 
       .end() 
       .build(); 
    } 

    @Bean 
    public JobCompletionNotificationListener AppJobCompletionNotificationListener() { 
     return new JobCompletionNotificationListener(); 
    } 

    @Bean 
    public TaskExecutor concurrentTaskExecutor() { 
     SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); 
     taskExecutor.setConcurrencyLimit(1); 
     return taskExecutor; 
    } 
} 

AppBatchNotificationItemProcessor.java

@StepScope 
public class AppBatchNotificationItemProcessor<E> extends AppAbstractItemProcessor<E, JAXBElement<ServiceRequestType>> implements ItemProcessor<E, JAXBElement<ServiceRequestType>>, StepExecutionListener { 

    // This is populated correctly 
    @Value("#{jobExecutionContext['" + Constants.SECURITY_TOKEN + "']}") 
    private SecurityToken securityToken; 

    @Autowired 
    private AppProcessorService processor; 

    @Override 
    public JAXBElement<ServiceRequestType> process(E item) throws BPException { 
     // Do Stuff 
     return srRequest; 
    } 

    @BeforeProcess 
    public void beforeProcess(E item) { 
     System.out.println("Doesn't execute"); 
    } 

    @Override 
    public void beforeStep(StepExecution stepExecution) { 
     // Doesn't execute 
     System.out.println("Doesn't execute"); 
    } 

    @Override 
    public ExitStatus afterStep(StepExecution stepExecution) { 
     // Doesn't execute 
     System.out.println("Doesn't execute"); 
    } 

} 

回答

1

這是由於您正在返回接口而不是您的@Bean方法中的實現。恕我直言,你應該返回在Spring中使用java配置時可能的最具體的類型。原因如下:

通過XML進行配置時,您可以在XML配置中提供該類。這將實現公開給Spring,以便可以發現並適當處理類實現的任何接口。在使用java配置時,@Bean方法的返回類型用作該信息的替換。還有問題。如果你的返回類型是一個接口,Spring只知道那個特定的接口,而不是實現可能實現的所有接口。通過返回具體類型,您可以讓Spring深入瞭解您實際返回的內容,從而更好地爲您處理各種註冊和配線用例。

對於您的具體示例,由於您返回的是ItemProcessor並且它的步驟範圍(因此是代理),所以Spring知道的是接口預期的方法/行爲。如果您返回實施(AppBatchNotificationItemProcessor),則可以自動配置其他行爲。

+0

謝謝邁克爾,那個工作。 –

0

至於我記得,你必須直接註冊一個讀者,作家,處理器爲收聽的一步,如果你使用StepScope。

StepScope阻止框架能夠找出什麼樣的接口, @annotations(例如@ BeforeProcess)代理實際上實現/定義,因此它不能將其註冊爲偵聽器。

所以,我想如果添加

return stepBuilderFactory.get("AppStep") 
      .<Object, JAXBElement<ServiceRequestType>> chunk(10) 
      .reader(appXmlReader(INPUT_XML_FILE_PATH_PLACEHOLDER)) 
      .processor(appNotificationProcessor()) 
      .writer(writer(OUTPUT_XML_FILE_PATH_PLACEHOLDER)) 

     .listener(appNotificationProcessor()) 

      .taskExecutor(concurrentTaskExecutor()) 
      .throttleLimit(1) 
      .build(); 

它會奏效。