当前位置: 首页 > 知识库问答 >
问题:

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

谷梁卓
2023-03-14

目前,我使用jobParameters获取FlatFileItemReader和FlatFileItemWriter的文件名。测试我的批处理是可以的,但是我的目标是读取某个目录中的文件(这个目录中只有这个文件),并且文件名可能会更改。输出文件名应该依赖于输入文件名。

因此,我考虑在我的工作中添加一个新的步骤,这个步骤将通过搜索好的目录并向其中查找文件来设置输出和输入文件名。我从Spring Doc读到向未来步骤传递数据,并且从SO读到这个线程,但是我不能使它工作,文件总是“空”。

首先,我定义了以下任务

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<RedevableCRE> flatFileWriter(@Value("#{jobExecutionContext[outputFile]}") String outputFile) {
    FlatFileItemWriter<Employee> flatWriter = new FlatFileItemWriter<Employee>();
    FileSystemResource isr;
    isr = new FileSystemResource(new File(outputFile));
    flatWriter.setResource(isr);
    DelimitedLineAggregator<RedevableCRE> aggregator = new DelimitedLineAggregator<RedevableCRE>();
    aggregator.setDelimiter(";");
    BeanWrapperFieldExtractor<RedevableCRE> beanWrapper = new BeanWrapperFieldExtractor<RedevableCRE>();
    beanWrapper.setNames(new String[]{
        "id", "firstName", "lastName", "phone", "address"
    });
    aggregator.setFieldExtractor(beanWrapper);
    flatWriter.setLineAggregator(aggregator);
    flatWriter.setEncoding("ISO-8859-1");
    return flatWriter;
}
@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();
}
[...]    
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.<init>(Unknown Source)
    at batchTest.BatchConfiguration.flatFileWriter(BatchConfiguration.java:165)
    at batchTest.BatchConfiguration$$EnhancerBySpringCGLIB$$5d415889.CGLIB$flatFileWriter$1(<generated>)
    at batchTest.BatchConfiguration$$EnhancerBySpringCGLIB$$5d415889$$FastClassBySpringCGLIB$$969a8527.invoke(<generated>)
    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(<generated>)
    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

我错过了什么?

谢谢你的帮助。

共有1个答案

于鸿博
2023-03-14

在tasklet中,您可以使用chunkcontext,因此您不需要@beforesteep,您可以删除它(在我的配置中,它根本没有被调用,并且当您将它视为一个动作时,步骤没有多大意义,但我没有看到NPE,所以猜测该部分工作)。我们用两种方法之一解决了这个问题:

>

  • 您可以直接使用chunkcontext.getstepcontext().getstepexecution().getjobexecution().getexecutioncontext().put(“inputfile”,inputFilename);将tasklet中的任何参数放入作业executioncontext

    您可以将ExecutionContextPromotionListener添加到任务步骤中,然后执行ChunkContext.GetStepContext().GetStepExecution().GetExecutionContext().Put(“InputFile”,inputFilename);

  •  类似资料:
    • 我有以下Spring批处理作业配置: 我用以下代码开始这项工作: 如何从作业步骤访问参数?

    • 我正在尝试在Spring批处理中并行运行多个作业。在谷歌上搜索了很多之后,我遇到了JobStep。有没有人使用过JobStep可以解释如何使用它来并行运行作业,或者有没有其他方法可以并行运行2个独立的作业,即当我启动批处理时,2个作业应该开始并行运行。我的要求就像 当我的应用程序启动时,两个作业都应该开始运行。使用spring batch是否可以这样做 编辑:我甚至试过这种方法 我面临着例外。sp

    • 我有一个spring批处理作业,它接收平面文件,处理记录,并将输出写入另一个平面文件。我分别使用了和作为读写器。然而,当我尝试实现多线程步骤时,我的工作无法正常工作。我在日志文件中收到以下警告 你能帮我实现多线程步骤吗?

    • 我是新的spring批处理,只是寻找一些帮助通过一个步骤之间的列表。在step 1 writer中,我将向ExecutionContext添加一个列表。 在第二步的阅读器中,我通过执行以下操作返回数据: 这样做起作用了,我得到了列表,但我遇到的问题是,我想把这个列表传递给处理器,但是ItemReader中的read()方法会连续循环返回列表,因为我只想返回一次列表。在这样做的同时,处理器也会循环。

    • null null 任何解决问题的帮助/指针都是非常感谢的。 谢谢,哈尔·克里尚

    • 我们正在实施Spring批量作业, 我们需要将作业参数从Client/MASTER传递给SLAVE。CLIENT/MASTER是我们的作业和分区代码所在的位置。我们使用传递JOB参数的J Unit调用JOB。 SLAVE是定义所有步骤及其实现(读取器Writer和处理器)的地方。 我们能够以独立的方式实现这一点,但不能与客户一起实现 我们正在使用Weblogic和Spring集成以及JMS来实现同