Skip to main content
Advertisement

15.2 Job, Step, Tasklet Lifecycle

Declaring Jobs and Steps as beans via Java Config is the standard Spring Batch configuration approach. In Spring Boot 3 (Batch 5.x), auto-configuration is active even without @EnableBatchProcessing.

1. Declaring Jobs and Steps (Spring Batch 5 Style)

@Configuration
@RequiredArgsConstructor
public class CouponInactiveBatchConfig {

private final JobRepository jobRepository;
private final PlatformTransactionManager transactionManager;
private final DataSource dataSource;

// 1. Job declaration
@Bean
public Job inactiveCouponJob(Step inactiveCouponStep) {
return new JobBuilder("inactiveCouponJob", jobRepository)
.incrementer(new RunIdIncrementer()) // Generate unique ID per run
.flow(inactiveCouponStep)
.end()
.build();
}

// 2. Step declaration (Chunk-based)
@Bean
public Step inactiveCouponStep() {
return new StepBuilder("inactiveCouponStep", jobRepository)
.<Coupon, Coupon>chunk(1000, transactionManager) // 1000 items per chunk
.reader(couponItemReader())
.processor(couponItemProcessor())
.writer(couponItemWriter())
.build();
}

// 3-1. Reader: Read expired coupons from DB in pages of 1000
@Bean
public JdbcPagingItemReader<Coupon> couponItemReader() {
return new JdbcPagingItemReaderBuilder<Coupon>()
.name("couponItemReader")
.dataSource(dataSource)
.selectClause("SELECT id, user_id, status, expire_date")
.fromClause("FROM coupons")
.whereClause("WHERE status = 'ACTIVE' AND expire_date < NOW()")
.sortKeys(Map.of("id", Order.ASCENDING))
.rowMapper(new BeanPropertyRowMapper<>(Coupon.class))
.pageSize(1000)
.build();
}

// 3-2. Processor: Change the status value
@Bean
public ItemProcessor<Coupon, Coupon> couponItemProcessor() {
return coupon -> {
coupon.setStatus("INACTIVE");
return coupon;
};
}

// 3-3. Writer: Bulk update the modified coupons
@Bean
public JdbcBatchItemWriter<Coupon> couponItemWriter() {
return new JdbcBatchItemWriterBuilder<Coupon>()
.dataSource(dataSource)
.sql("UPDATE coupons SET status = :status WHERE id = :id")
.beanMapped()
.build();
}
}

2. Manual Job Trigger (API or Scheduler)

@RestController
@RequiredArgsConstructor
public class BatchController {

private final JobLauncher jobLauncher;
private final Job inactiveCouponJob;

@PostMapping("/admin/batch/inactive-coupons")
public ResponseEntity<String> runBatch() throws Exception {
JobParameters params = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis()) // Different params allow re-runs
.toJobParameters();

jobLauncher.run(inactiveCouponJob, params);
return ResponseEntity.ok("Batch execution complete");
}
}
Advertisement