【Java】SpringBatch 纯纯的笔记

  • 一个 Job 由多个 Step 组成
  • Step 有两种实现方式:TaskletRead-Process-Write
  • 两种实现方式可以单独使用,也可以一起使用
  • Spring Batch 提供了 skip 和 retry 机制

使用 Tasklet

Tasklet 只会执行一次,实现org.springframework.batch.core.step.tasklet.Tasklet接口,在execute方法中编写逻辑
当 Tasklet 实现类返回RepeatStatus.FINISHED,Job 会执行下一个 Step

@Configuration
@EnableBatchProcessing
public class MyJobConfiguration {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                .tasklet((stepContribution, chunkContext) -> {
                    // Step1的逻辑
                    return RepeatStatus.FINISHED;
                }).build();
    }

    @Bean
    public Step step2() {
        return stepBuilderFactory.get("step2")
                .tasklet((stepContribution, chunkContext) -> {
                    // Step2的逻辑
                    return RepeatStatus.FINISHED;
                }).build();
    }

    @Bean
    public Step step3() {
        return stepBuilderFactory.get("step3")
                .tasklet((stepContribution, chunkContext) -> {
                    // Step3的逻辑
                    return RepeatStatus.FINISHED;
                }).build();
    }

    @Bean
    public Job myJob() {
        return jobBuilderFactory.get("myJob")
                .start(step1())
                .next(step2())
                .next(step3())
                .build();
    }
}

使用 Read-Process-Write

Read-Process-Write 会执行多次,chunk(int chunkSize)中的值表示一次 Read-Process-Write 的处理量
此次使用FlatFileItemReader读数据,JpaItemWriter写数据

public class MessageProcessor implements ItemProcessor<Message, Message> {
    @Override
    public Message process(Message item) {
        System.out.println("item: " + item.toString());
        return item;
    }
}
public class MessageItemReadListener implements ItemReadListener<Message> {
	//
}
public class MessageWriteListener implements ItemWriteListener<Message> {
	//
}
public class MessageLineMapper implements LineMapper<Message> {
    //
}
public class Message {
    //
}
public class MessageMigrationJobConfiguration {

    private static final Integer CHUNK_SIZE = 4;
    private static final String MESSAGE_FILE = "src/main/resources/file/message.txt";
    private static final Integer SKIP_LIMIT = 1;

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    private EntityManagerFactory entityManager;

    /**
     * @Description: 构建job
     */
    @Bean
    public Job messageMigrationJob(@Qualifier("messageMigrationStep") Step messageMigrationStep) {
        return jobBuilderFactory.get("messageMigrationJob")
                .flow(messageMigrationStep)
                .end()
                .build();
    }

    /**
     * @Description: 构建step
     */
    @Bean
    public Step messageMigrationStep(@Qualifier("jsonMessageReader") FlatFileItemReader<Message> jsonMessageReader,
                                     @Qualifier("messageProcessor") MessageProcessor messageProcessor,
                                     @Qualifier("messageItemWriter") JpaItemWriter<Message> messageItemWriter) {
        return stepBuilderFactory.get("messageMigrationStep")
                .<Message, Message>chunk(CHUNK_SIZE)
                .reader(jsonMessageReader).faultTolerant().skip(JsonParseException.class).skipLimit(SKIP_LIMIT)
                .listener(new MessageItemReadListener())
                .processor(messageProcessor)
                .writer(messageItemWriter).faultTolerant().skip(Exception.class).skipLimit(SKIP_LIMIT)
                .listener(new MessageWriteListener())
                .build();
    }

    /**
     * @Description: 构建reader
     * FlatFileItemReader:从文件里面一行一行的读取数据
     * .setResource:设置文件路径
     * .setLineMapper:把一行文本映射为Message类,自定义类
     */
    @Bean
    public FlatFileItemReader<Message> jsonMessageReader() {
        FlatFileItemReader<Message> reader = new FlatFileItemReader<>();
        reader.setResource(new FileSystemResource(new File(MESSAGE_FILE)));
        reader.setLineMapper(new MessageLineMapper());
        return reader;
    }

    @Bean
    public MessageProcessor messageProcessor() {
        return new MessageProcessor();
    }

    /**
     * @Description: 构建writer
     */
    @Bean
    public JpaItemWriter<Message> messageItemWriter() {
        JpaItemWriter<Message> writer = new JpaItemWriter<>();
        writer.setEntityManagerFactory(entityManager);
        return writer;
    }
}

注解

  • @EnableBatchProcessing打开Batch。如果多 job 的情况,需要把 EnableBatchProcessing 注解的 modular 设置为 true ,让每个 Job 使用自己的 ApplicationConext
  • @JobScope作用域注解。应用于 step 或 reader、processor、writer 等组件的 @Bean 方法中,用于指定组件的生命周期范围为 Job。使用 @JobScope 注解的组件,将在 Job 执行期间实例化一次,然后在 Job 执行完成后销毁。这使得组件可以拥有 Job 的上下文,包括 JobParameters、ExecutionContext 等,从而可以在 Job 执行期间获取 Job 的相关信息。

常用类

  • JobLauncher启动 job 类
  • JobRegistry存储多个 job 实例,JobRegistry 可以通过 job 实例的唯一名称获取 job
  • JobBuilderFactory构建 JobBuilder 对象的工厂类
    • 通常用JobBuilder get(String name)构建 JobBuilder
  • StepBuilderFactory构建 StepBuilder 对象的工厂类
    • 通常用StepBuilder get(String name)构建 StepBuilder

JobParameters

存储一组有序的键值对,这些键值用于 Job 或 Step 的运行时参数

@Autowired
private JobLauncher jobLauncher;

public void executeJob(Job job) {
    JobParameters params = new JobParametersBuilder()
        .addLong(key, value, true)
        .addString(key, value, true)
        .toJobParameters();
    
    jobLauncher.run(job, params)
}
  • 在构建 job 时(或step/tasklet/chunk/reader...)需要参数信息,使用@Value("#{jobParameters['...']}")注解的方式注入
  • 需要使用@JobScope注解
@Bean
@JobScope
ItemProcessor<Xxx, Xxx> processor(@Value("#{jobParameters['Xxx']}") String Xxx,
                                  @Value("#{jobParameters['Xxx']}") String Xxx) {
    return null;
}

JobBuilder

用来创建 Job 实例

常用方法👇

  1. name(String name)为Job实例指定名称
  2. incrementer(JobParametersIncrementer incrementer)指定 JobParametersIncrementer 实例,用于生成 Job 参数
  3. start(Step step)返回 SimpleJobBuilder,指定 Job 实例的第一个 Step 实例
  4. flow(Step step)返回 JobFlowBuilder,指定 Job 实例的第一个 Step 实例
  5. listener(JobExecutionListener listener)指定 JobExecutionListener 实例,用于监听 Job 的执行
  6. listener(StepExecutionListener listener)指定 StepExecutionListener 实例,用于监听 Job 的每个 Step 的执行
  7. validator(JobParametersValidator validator)指定 JobParametersValidator 实例,用于验证 Job 参数的合法性
  8. build()构建 Job 实例

Job

Job 有以下几种:

  1. SimpleJob包含一个 Step,执行完 Step 后即结束
  2. FlowJob包含多个 Step 组成的逻辑流,根据 Step 执行结果状态,通过决策器实现分支
  3. SplitJob包含多个 Step,这些 Step 可以并行执行
  4. ChildJob在一个 Job 中可以包含其他 Job,形成树形结构,父Job 可以决定 子Job 的执行顺序和执行条件
  5. CompositeJob通过讲多个 Job 组合在一起,实现一个 Job 包含多个 子Job 的效果,子Job 可以并行或串行执行,相互独立

p.s. 这些 Job 之间并不是互斥的,可以混合使用。可以使用JobStepBuilder将一个 Job 封装成 Step,然后在另一个 Job 中引用这个 Step

StepBuilder

用来创建 Step 实例

常用方法👇

  1. tasklet(Tasklet tasklet)指定 Step 中使用的 Tasklet,每个 Step 至少要有一个 Tasklet
  2. chunk(int chunkSize)指定每次读取多少数据进行处理,以及处理完后一次性写出的数据量
  3. reader(ItemReader<? extends T> itemReader)指定 Step 中使用的 ItemReader
  4. processor(ItemProcessor<? super T, ? extends S> itemProcessor)指定 Step 中使用的 ItemProcessor
  5. writer(ItemWriter<? super S> itemWriter)指定 Step 中使用的 ItemWriter
  6. allowStartIfComplete(boolean allowStart)是否允许 Step 在上一次执行完成后立即再次执行
  7. flow(Flow flow)返回 FlowStepBuilder,指定 Step 的 Flow 实例

Step

Step 有以下几种:

  1. SimpleStep指定读、处理、写操作【单线程】
  2. ChunkOrientedTasklet可以包揽读、处理、写操作【单线程】
  3. TaskletStep指定并执行一个 Tasklet【单线程】
  4. FlowStep中有一个 Flow 实例,Flow 实例中可以有多个 Step,可进行条件控制,如跳过某些步骤、重试某些步骤等【单线程】

多线程的 Step 有SimpleAsyncTaskExecutorStepTaskExecutorStepPartitionStep

Listener

Listener 接口需要实现使用,都有beforeXxxafterXxx方法。在对应位置使用,如 Step 的监听器,在创建 Step 时使用;Job 的监听器,在创建 Job 时使用
常用接口👇

  1. StepExecutionListenerstep 执行监听器
  2. ItemReadListenerstep 监听器
  3. ItemWriteListenerstep 监听器
  4. JobExecutionListenerjob 执行监听器

ItemReader

step 的读操作,SpringBatch 提供多个实现类👇

  1. JdbcCursorItemReader用于从 JDBC 游标检索结果集
  2. JdbcPagingItemReader用于从 JDBC 分页检索结果集
  3. HibernateCursorItemReader用于从 Hibernate 游标检索结果集
  4. HibernatePagingItemReader用于从 Hibernate 分页检索结果集
  5. JpaPagingItemReader用于从 JPA 分页检索结果集
  6. FlatFileItemReader用于从文件中读取数据
  7. StaxEventItemReader读取 XML 文件
  8. JsonItemReader读取 Json 格式数据

自定义 ItemReader:实现 ItemReader 接口,并重写 read 方法,该方法需要返回一个对象,如果没有读到数据则返回 null

ItemWriter

step 的写操作,SpringBatch 提供多个实现类👇

  1. JdbcBatchItemWriter将数据批量写入关系型数据库
  2. JpaItemWriter将数据批量写入 JPA 实体类
  3. HibernateItemWriter将数据批量写入 Hibernate 实体类
  4. FlatFileItemWriter将数据写入文本文件
  5. MultiResourceItemWriter将数据写入多个文件
  6. MongoItemWriter将数据批量写入 MongoDB
  7. HdfsTextItemWriter将数据写入 HDFS 文件

自定义 ItemWriter:通过实现 ItemWriter 接口,并重写 write 方法

posted @ 2023-03-01 17:31  洗衣机o  阅读(572)  评论(0)    收藏  举报