【Java】SpringBatch 纯纯的笔记
- 一个 Job 由多个 Step 组成
- Step 有两种实现方式:
Tasklet和Read-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 实例的唯一名称获取 jobJobBuilderFactory构建 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 实例
常用方法👇
name(String name)为Job实例指定名称incrementer(JobParametersIncrementer incrementer)指定 JobParametersIncrementer 实例,用于生成 Job 参数start(Step step)返回 SimpleJobBuilder,指定 Job 实例的第一个 Step 实例flow(Step step)返回 JobFlowBuilder,指定 Job 实例的第一个 Step 实例listener(JobExecutionListener listener)指定 JobExecutionListener 实例,用于监听 Job 的执行listener(StepExecutionListener listener)指定 StepExecutionListener 实例,用于监听 Job 的每个 Step 的执行validator(JobParametersValidator validator)指定 JobParametersValidator 实例,用于验证 Job 参数的合法性build()构建 Job 实例
Job
Job 有以下几种:
SimpleJob包含一个 Step,执行完 Step 后即结束FlowJob包含多个 Step 组成的逻辑流,根据 Step 执行结果状态,通过决策器实现分支SplitJob包含多个 Step,这些 Step 可以并行执行ChildJob在一个 Job 中可以包含其他 Job,形成树形结构,父Job 可以决定 子Job 的执行顺序和执行条件CompositeJob通过讲多个 Job 组合在一起,实现一个 Job 包含多个 子Job 的效果,子Job 可以并行或串行执行,相互独立
p.s. 这些 Job 之间并不是互斥的,可以混合使用。可以使用JobStepBuilder将一个 Job 封装成 Step,然后在另一个 Job 中引用这个 Step
StepBuilder
用来创建 Step 实例
常用方法👇
tasklet(Tasklet tasklet)指定 Step 中使用的 Tasklet,每个 Step 至少要有一个 Taskletchunk(int chunkSize)指定每次读取多少数据进行处理,以及处理完后一次性写出的数据量reader(ItemReader<? extends T> itemReader)指定 Step 中使用的 ItemReaderprocessor(ItemProcessor<? super T, ? extends S> itemProcessor)指定 Step 中使用的 ItemProcessorwriter(ItemWriter<? super S> itemWriter)指定 Step 中使用的 ItemWriterallowStartIfComplete(boolean allowStart)是否允许 Step 在上一次执行完成后立即再次执行flow(Flow flow)返回 FlowStepBuilder,指定 Step 的 Flow 实例
Step
Step 有以下几种:
SimpleStep指定读、处理、写操作【单线程】ChunkOrientedTasklet可以包揽读、处理、写操作【单线程】TaskletStep指定并执行一个 Tasklet【单线程】FlowStep中有一个 Flow 实例,Flow 实例中可以有多个 Step,可进行条件控制,如跳过某些步骤、重试某些步骤等【单线程】
多线程的 Step 有SimpleAsyncTaskExecutorStep、TaskExecutorStep、PartitionStep
Listener
Listener 接口需要实现使用,都有beforeXxx和afterXxx方法。在对应位置使用,如 Step 的监听器,在创建 Step 时使用;Job 的监听器,在创建 Job 时使用
常用接口👇
StepExecutionListenerstep 执行监听器ItemReadListenerstep 读监听器ItemWriteListenerstep 写监听器JobExecutionListenerjob 执行监听器
ItemReader
step 的读操作,SpringBatch 提供多个实现类👇
JdbcCursorItemReader用于从 JDBC 游标检索结果集JdbcPagingItemReader用于从 JDBC 分页检索结果集HibernateCursorItemReader用于从 Hibernate 游标检索结果集HibernatePagingItemReader用于从 Hibernate 分页检索结果集JpaPagingItemReader用于从 JPA 分页检索结果集FlatFileItemReader用于从文件中读取数据StaxEventItemReader读取 XML 文件JsonItemReader读取 Json 格式数据
自定义 ItemReader:实现 ItemReader 接口,并重写 read 方法,该方法需要返回一个对象,如果没有读到数据则返回 null
ItemWriter
step 的写操作,SpringBatch 提供多个实现类👇
JdbcBatchItemWriter将数据批量写入关系型数据库JpaItemWriter将数据批量写入 JPA 实体类HibernateItemWriter将数据批量写入 Hibernate 实体类FlatFileItemWriter将数据写入文本文件MultiResourceItemWriter将数据写入多个文件MongoItemWriter将数据批量写入 MongoDBHdfsTextItemWriter将数据写入 HDFS 文件
自定义 ItemWriter:通过实现 ItemWriter 接口,并重写 write 方法

浙公网安备 33010602011771号