开发者社区> 问答> 正文

Spring Batch和SystemCommandTasklet:无法传递参数

我试图从rest控制器触发spring batch作业,我需要将参数传递给Step。我用了一个SystemCommandTasklet和,作为建议在这里我加入了微进程作为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]

beforeStepTasklet中的方法永远不会被调用,这会导致NPE。

这是我的批处理配置:

@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;
    }

}

我尝试了数十种不同的方法来执行此操作,但是我仍然无法弄清楚为什么beforeStep未调用Tasklet中的方法并且execution仍然保留该字段null

问题来源:Stack Overflow

展开
收起
montos 2020-03-22 12:25:43 864 0
1 条回答
写回答
取消 提交回答
  • 您的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。

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

    回答来源:Stack Overflow

    2020-03-22 12:26:21
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧 立即下载
微服务架构模式与原理Spring Cloud开发实战 立即下载
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库 立即下载

相关实验场景

更多