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

Spring batch和SystemCommandTasklet:不能传递参数

缑嘉玉
2023-03-14

我试图从rest控制器触发一个spring批处理作业,我需要向步骤传递参数。我使用了一个SystemCommandTasklet,正如这里所建议的那样,我将该Tasklet添加为StepListener,但我一直得到一个NPE。

我在这里创建了一个示例项目:如果您运行测试,您将在输出中看到以下内容:

java.lang.NullPointerException: null
    at org.springframework.batch.core.step.tasklet.SystemCommandTasklet.execute(SystemCommandTasklet.java:133) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at com.sun.proxy.$Proxy87.execute(Unknown Source) ~[na:na]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.2.4.RELEASE.jar:5.2.4.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:410) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:319) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:147) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
@Configuration
@EnableBatchProcessing
public class BatchConfiguration extends DefaultBatchConfigurer {

    private final JobBuilderFactory jobBuilderFactory;

    private final StepBuilderFactory stepBuilderFactory;

    public BatchConfiguration(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
    }

    @Override
    public JobLauncher getJobLauncher() {
        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
        jobLauncher.setJobRepository(getJobRepository());
        jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return jobLauncher;
    }

    @Bean
    public Job myJob(Step myStep) {
        return jobBuilderFactory.get("myJob")
                .incrementer(new RunIdIncrementer())
                .start(myStep)
                .build();
    }

    @Bean
    public Step myStep(Tasklet myServiceTasklet) {
        return this.stepBuilderFactory.get("myStep")
                .listener(myServiceTasklet)
                .tasklet(myServiceTasklet)
                .build();
    }

    @Bean
    @StepScope
    public Tasklet myServiceTasklet(
             @Value("#{jobParameters['my_param']}") String param
    ) {
        SystemCommandTasklet tasklet = new SystemCommandTasklet();
        System.out.println(param);
        tasklet.setCommand("sleep 10");
        tasklet.setTimeout(20000);
        return tasklet;
    }

}

共有1个答案

欧照
2023-03-14

您的tasklet bean定义方法的返回类型应该是SystemCommandTasklet:

@Bean
@StepScope
public SystemCommandTasklet myServiceTasklet(
         @Value("#{jobParameters['my_param']}") String param
) {
    SystemCommandTasklet tasklet = new SystemCommandTasklet();
    System.out.println(param);
    tasklet.setCommand("sleep 10");
    tasklet.setTimeout(20000);
    return tasklet;
}

目前,它返回tasklet,因此Spring Batch不会将它作为StepExecutionListener代理(这就是为什么它没有注册为监听器,也没有调用BeforeStep方法)。

您需要尽可能明确bean定义方法的返回类型,以便Spring Batch能够正确地代理bean并用正确的类型注册它们。更多详细信息请参见:https://stackoverflow.com/a/21941127/5019386。

注意:我下载了您的代码,并注意到您不会像在测试代码中那样在启动时禁用生产代码中的作业。您还需要在src/main/resources中添加相同的application.properties

 类似资料:
  • 在使用RestAssured的cucumber api测试中,我试图将路径参数作为空/空传递。 例如,当我以>>http://localhost:8093/my-rest-call//指令调用endpoint时 它给404但我希望是500。在《邮递员》中,它和预期的一样工作 但是,如果末尾的path参数为null/empty。如下所示,我得到了500个内部服务器错误。 我尝试的其他选项是have“

  • 问题内容: 我在很多地方都看到过,包括Python使用的Python文档通过“赋值”语义传递。来自Java背景,说“ Java按值传递基元,按引用传递对象”的常见错误是由于按值传递了对象引用,我不禁怀疑Python是否真的在做同样的事情事情。 在我看来,按值传递对象引用和按赋值传递对象的概念似乎相同。Python使用术语“传递分配”是否是为了减轻诸如我上面所述的错误语句的问题?如果是这样,可以公平

  • 我目前正在尝试将我的Firebase数据库中的内容读入中,但我希望将它们从最后一个节点加载到第一个节点。所以我决定将键放入一个数组中,然后尝试从数组的末尾读到前面,但是当我尝试访问键数组时,我看到的是中的参数'path string'传递null错误。

  • 您可以将其他数据作为常规方法参数传递到后台任务。我再次使用下面的例子(希望没有让你厌恶): BackgroundJob.Enqueue(() => Console.WriteLine("Hello, {0}!", "world")); 在常规方法调用中,在执行后台作业期间, Console.WriteLine 方法将使用这些参数。为了参数传递进去,需要先序列化。 使用 了不起的 Newtonsof

  • 用例:步骤1:ItemReader:从数据库中读取1000个ItemProcessor块中的数据:处理这些数据。ItemWriter:将数据写入地图,以便下一步使用 步骤2:ItemReader:读取地图ItemProcessor:处理地图数据并获取新对象。ItemWriter:将新的进程对象持久化到数据库中。 现在我希望Map在整个作业中保持不变,目前我已经为Map创建了一个不同的POJO类,并

  • 问题内容: 我正在使用py.test来测试包装在python类MyTester中的某些DLL代码。为了进行验证,我需要在测试期间记录一些测试数据,然后再进行更多处理。由于我有许多test _…文件,因此我想在大多数测试中重用测试器对象的创建(MyTester的实例)。 由于tester对象是获得DLL变量和函数的引用的对象,因此我需要将DLL变量的列表传递给每个测试文件的tester对象(要记录的