从tasklet步骤向作业上下文添加参数,并在Spring Batch的后续步骤中使用

现在,我正在使用jobParameters来获取我的FlatFileItemReader和FlatFileItemWriter的文件名。 可以测试我的批处理,但我的目标是读取某个目录中的文件(此目录中只有此文件),文件名可能会更改。 输出文件名应取决于输入文件名。

因此,我考虑在我的工作中添加一个新步骤,此步骤将通过搜索好目录并在其中查找文件来设置输出和输入文件名。 我从Spring Doc读取了将数据传递给Future Steps ,以及来自SO的这个post ,但是我无法使它工作,文件总是“空”。

首先,我定义了以下Tasklet

public class SettingFilenamesTasklet implements Tasklet { private StepExecution stepExecution; @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { // TODO Search folder and set real filenames String inputFilename = "D:/TestInputFolder/dataFile.csv"; String outputFilename = "D:/TestOutputFolder/dataFile-processed.csv"; ExecutionContext stepContext = stepExecution.getExecutionContext(); stepContext.put("inputFile", inputFilename); stepContext.put("outputFile", outputFilename); return RepeatStatus.FINISHED; } @BeforeStep public void saveStepExecution(StepExecution stepExec) { stepExecution = stepExec; } } 

然后,我添加了promotionListener bean

 @Bean public ExecutionContextPromotionListener promotionListener() { ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener(); listener.setKeys(new String[]{ "inputFile", "outputFile" }); return listener; } 

我在我的FlatFileItemWriter定义中通过jobExecutionContext更改了jobParameters(我没有将一行更改为代码本身)

 @Bean @StepScope public FlatFileItemWriter flatFileWriter(@Value("#{jobExecutionContext[outputFile]}") String outputFile) { FlatFileItemWriter flatWriter = new FlatFileItemWriter(); FileSystemResource isr; isr = new FileSystemResource(new File(outputFile)); flatWriter.setResource(isr); DelimitedLineAggregator aggregator = new DelimitedLineAggregator(); aggregator.setDelimiter(";"); BeanWrapperFieldExtractor beanWrapper = new BeanWrapperFieldExtractor(); beanWrapper.setNames(new String[]{ "id", "firstName", "lastName", "phone", "address" }); aggregator.setFieldExtractor(beanWrapper); flatWriter.setLineAggregator(aggregator); flatWriter.setEncoding("ISO-8859-1"); return flatWriter; } 

我添加了我的Tasklet bean

 @Bean public SettingFilenamesTasklet settingFilenames() { return new SettingFilenamesTasklet(); } 

我创建了一个新的步骤来添加我的工作声明

 @Bean public Step stepSettings(StepBuilderFactory stepBuilderFactory, SettingFilenamesTasklet tasklet, ExecutionContextPromotionListener listener) { return stepBuilderFactory.get("stepSettings").tasklet(tasklet).listener(listener).build(); } 

目前,FlatFileItemReader仍然使用jobParameters值,我想让我的FlatFileItemWriter先工作。 我收到以下错误:

 [...] Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.item.file.FlatFileItemWriter]: Factory method 'flatFileWriter' threw exception; nested exception is java.lang.NullPointerException at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:591) ... 87 common frames omitted Caused by: java.lang.NullPointerException: null at java.io.File.(Unknown Source) at batchTest.BatchConfiguration.flatFileWriter(BatchConfiguration.java:165) at batchTest.BatchConfiguration$$EnhancerBySpringCGLIB$$5d415889.CGLIB$flatFileWriter$1() at batchTest.BatchConfiguration$$EnhancerBySpringCGLIB$$5d415889$$FastClassBySpringCGLIB$$969a8527.invoke() at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312) at batchTest.BatchConfiguration$$EnhancerBySpringCGLIB$$5d415889.flatFileWriter() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ... 88 common frames omitted 

我试图用@JobScope替换@StepScope注释; 将我的参数直接放入jobExecutionContext(+ JobExecutionListener)而不是使用StepContext + promotionListener ……没有任何作用。 当我尝试创建FlatFileItemWriter时,资源文件始终为null。

我错过了什么?

谢谢你的帮助。

在tasklet中你可以使用ChunkContext ,所以你不需要@BeforeStep ,你可以删除它(在我的配置中它根本不被调用,当你把它想象为一个动作步骤没有多大意义但是我没有看到NPE所以猜测那部分工作)。 我们用两种方法之一解决了这个问题:

  1. 您可以使用chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().put("inputFile", inputFilename);直接将任何参数从tasklet放入作业ExecutionContext chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().put("inputFile", inputFilename);

  2. 您可以将ExecutionContextPromotionListener添加到您的tasklet步骤,然后执行chunkContext.getStepContext().getStepExecution().getExecutionContext().put("inputFile", inputFilename);