如何在运行时创建和启动Spring批处理作业

时间:2017-06-21 12:43:32

标签: java spring spring-batch etl

我们要求从1个数据库到其他数据库进行数据移动,并探索相同的弹簧批次。我们的应用程序的用户选择源和目标数据源以及需要移动数据的表的列表。

需要以下帮助:

  1. 构建作业所需的信息来自我们的Web应用程序 - 包括数据源详细信息和表名列表。我们希望通过将这些详细信息发送到作业构建器模块并使用JobLauncher启动它来创建新作业。我们如何编写此作业构建器模块?
  2. 我们可能有多个用户并行提出数据移动请求,因此需要一种方法来创建多个作业并按合适的顺序运行它们。
  3. 我们使用基于Java的配置来创建作业并从Web容器启动它。配置如下

    @Bean
    public Job loadDataJob(JobCompletionNotificationListener listener) {
        RunIdIncrementer inc = new RunIdIncrementer();
        inc.setKey(new Date().toString());
        JobBuilder builder = jobBuilderFactory.get("loadDataJob")
                .incrementer(inc)
                .listener(listener);
        SimpleJobBuilder simpleBuilder = builder.start(preExecute());
        for(String s : getTables()){
            simpleBuilder.next(etlTable(s));
        }
        simpleBuilder.next(postExecute());
        return simpleBuilder.build();
    }
    
    @Bean
    @Scope("prototype")
    public Step etlTable(String tableName) {
        return stepBuilderFactory.get(tableName)
                .<Map<String,Object>, Map<String,Object>> chunk(1000)
                .reader(dbDataReader(tableName))
                .processor(processor())
                .writer(dbDataWriter(tableName))
                .build();
    }
    

    目前,我们已将源和目标数据源详细信息硬编码到相应的bean中。 getTables()返回需要移动数据的表(硬编码)列表。

    启动作业的RestController

        @RestController
    public class MyController {
        @Autowired
        JobLauncher jobLauncher;
    
        @Autowired
        Job job;
    
        @RequestMapping("/launchjob")
        public String handle() throws Exception {
            try {
                JobParameters jobParameters = new JobParametersBuilder().addLong("time", new Date().getTime()).toJobParameters();
                jobLauncher.run(job, jobParameters);
            } catch (Exception e) {
    
            }
    
            return "Done";
        }
    }
    

2 个答案:

答案 0 :(得分:2)

关于您的第一个问题,您肯定必须使用JavaConfiguration。此外,如果要创建具有动态步数的作业(例如,每个表必须复制一个步骤),则不应将步骤定义为spring bean。

我已经就如何动态创建工作的问题写了几个答案。看看他们,他们可能会有所帮助

<强>被修改
关于你的第二个问题的一些评论:

首先,您正在使用普通的JobLauncher,并假设您实例化了SimpleJobLauncher。这意味着,您可以提供作业参数的作业,如上面的代码所示。但是,所提供的工作&#34;不必是&#34; SpringBean&#34; -instance,因此您不必自动加载它,因此,您可以使用我在上述问题的答案中建议的create-methodes。 / p>

其次,如果您为每个请求动态创建Job实例,则无需将整个配置作为jobparameters传递,因为您可以传递&#34;配置属性&#34;比如数据源和表格作为参数直接复制到你的&#34; createJob&#34;方法。如果您事先并不了解所有可能的数据源,您甚至可以动态创建数据源实例#34;

第三,我会将每个请求视为&#34;单次运行&#34;,但不能重新启动&#34;。因此,我只是一些元信息&#34;进入工作参数,如用户,日期/时间,数据源名称(URL)和要复制的表列表。我会使用这种信息作为一种请求发布的日志/审计,但我不会将作业参数实例用作作业本身内部的控制参数(同样,您可以在期间传递这些参数的值)作业的构造时间和步骤通过将它们传递给您的创建方法,因此您的作业结构是根据您的参数创建的,因此,在运行时 - 当您可以访问您的作业参数时 - 基于jobparameters)。

最后,如果请求失败(意味着作业退出并出现错误),则只需执行一个新请求即可重试,但此请求将是一个完整的新请求,而不是重新启动已执行的作业启动(因为我会将请求时间添加到我的工作参数中,每次启动都会是一次独特的启动。)

已编辑2: 不创建作为Bean的作业并不意味着不使用自动装配。这是一个例子,我将构建我的豆。

@Component
@EnableBatchProcessing
@Import() // list with imports as neede
public class JobCreatorComponent {

  @Autowire
  private StepBuilderFactory stepBuilder;

  @Autowire
  private JobBuilderFactory jobBuilder;

  public Job createJob(all the parameters you need) {
     return jobBuilder.get(). ....
  }
}

@RestController
@Import(JobCreatorComponent.class)
public class MyController {
    @Autowired
    JobLauncher jobLauncher;

    @Autowired
    JobCreatorComponent jobCreator;

    @RequestMapping("/launchjob")
    public String handle() throws Exception {
        try {
            Job job = jobCreator.createJob(... params ...);
            JobParameters jobParameters = new JobParametersBuilder().addLong("time", new Date().getTime()).toJobParameters();
            jobLauncher.run(job, jobParameters);
        } catch (Exception e) {

        }

        return "Done";
    }
}

答案 1 :(得分:0)

在itemreader上使用@JobScope无需在运行时手动执行操作只需使用@Jobscope为您的相应阅读器添加注释,在与控制器的每次交互中,您都将获得新的记录处理。

这是一种按需作业类型,您可以在其中执行作业,例如进行数据库迁移或获取类似的特定报告。