Improve Step/Job builder APIs to guide users to set mandatory properties
Before this commit, the user had to manually set the job repository and transaction manager on `JobBuilder` and `StepBuilder` instances with a chained call to `.repository(jobRepository)` and `.transactionManager(transactionManager)`. This is error prone and can lead to runtime errors if these properties are not set. This commit introduces new APIs to guide the user to set these properties at builder creation time. Resolves #4192
This commit is contained in:
@@ -45,14 +45,13 @@ public class RetrySampleConfiguration {
|
||||
|
||||
@Bean
|
||||
public Job retrySample(JobRepository jobRepository) {
|
||||
return new JobBuilder("retrySample").repository(jobRepository).start(step(jobRepository)).build();
|
||||
return new JobBuilder("retrySample", jobRepository).start(step(jobRepository)).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected Step step(JobRepository jobRepository) {
|
||||
return new StepBuilder("step").repository(jobRepository).<Trade, Object>chunk(1)
|
||||
.transactionManager(this.transactionManager).reader(reader()).writer(writer()).faultTolerant()
|
||||
.retry(Exception.class).retryLimit(3).build();
|
||||
return new StepBuilder("step", jobRepository).<Trade, Object>chunk(1, this.transactionManager).reader(reader())
|
||||
.writer(writer()).faultTolerant().retry(Exception.class).retryLimit(3).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
@Configuration
|
||||
public class Job1Configuration {
|
||||
@@ -36,24 +37,24 @@ public class Job1Configuration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job job1(JobRepository jobRepository) {
|
||||
return new JobBuilder("job1").repository(jobRepository).start(step1(jobRepository)).next(step2(jobRepository))
|
||||
.build();
|
||||
public Job job1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
return new JobBuilder("job1", jobRepository).start(step1(jobRepository, transactionManager))
|
||||
.next(step2(jobRepository, transactionManager)).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step step1(JobRepository jobRepository) {
|
||||
return new StepBuilder("step1").repository(jobRepository).tasklet((contribution, chunkContext) -> {
|
||||
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
return new StepBuilder("step1", jobRepository).tasklet((contribution, chunkContext) -> {
|
||||
System.out.println("hello");
|
||||
// simulate processing time
|
||||
Thread.sleep(random.nextInt(3000));
|
||||
return RepeatStatus.FINISHED;
|
||||
}).build();
|
||||
}, transactionManager).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step step2(JobRepository jobRepository) {
|
||||
return new StepBuilder("step2").repository(jobRepository).tasklet((contribution, chunkContext) -> {
|
||||
public Step step2(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
return new StepBuilder("step2", jobRepository).tasklet((contribution, chunkContext) -> {
|
||||
System.out.println("world");
|
||||
// simulate step failure
|
||||
int nextInt = random.nextInt(3000);
|
||||
@@ -62,7 +63,7 @@ public class Job1Configuration {
|
||||
throw new Exception("Boom!");
|
||||
}
|
||||
return RepeatStatus.FINISHED;
|
||||
}).build();
|
||||
}, transactionManager).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
@Configuration
|
||||
public class Job2Configuration {
|
||||
@@ -40,14 +41,14 @@ public class Job2Configuration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job job2(JobRepository jobRepository) {
|
||||
return new JobBuilder("job2").repository(jobRepository).start(step(jobRepository)).build();
|
||||
public Job job2(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
return new JobBuilder("job2", jobRepository).start(step(jobRepository, transactionManager)).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step step(JobRepository jobRepository) {
|
||||
return new StepBuilder("step1").repository(jobRepository).<Integer, Integer>chunk(3).reader(itemReader())
|
||||
.writer(itemWriter()).build();
|
||||
public Step step(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
|
||||
return new StepBuilder("step1", jobRepository).<Integer, Integer>chunk(3, transactionManager)
|
||||
.reader(itemReader()).writer(itemWriter()).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import static org.springframework.data.mongodb.core.query.Criteria.where;
|
||||
|
||||
@@ -60,15 +61,15 @@ public class DeletionJobConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step deletionStep(JobRepository jobRepository, MongoItemReader<Person> mongoPersonReader,
|
||||
MongoItemWriter<Person> mongoPersonRemover) {
|
||||
return new StepBuilder("step").repository(jobRepository).<Person, Person>chunk(2).reader(mongoPersonReader)
|
||||
.writer(mongoPersonRemover).build();
|
||||
public Step deletionStep(JobRepository jobRepository, PlatformTransactionManager transactionManager,
|
||||
MongoItemReader<Person> mongoPersonReader, MongoItemWriter<Person> mongoPersonRemover) {
|
||||
return new StepBuilder("step", jobRepository).<Person, Person>chunk(2, transactionManager)
|
||||
.reader(mongoPersonReader).writer(mongoPersonRemover).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job deletionJob(JobRepository jobRepository, Step deletionStep) {
|
||||
return new JobBuilder("deletionJob").repository(jobRepository).start(deletionStep).build();
|
||||
return new JobBuilder("deletionJob", jobRepository).start(deletionStep).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.batch.item.data.builder.MongoItemWriterBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* This job will copy documents from collection "person_in" into collection "person_out"
|
||||
@@ -55,15 +56,15 @@ public class InsertionJobConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step step(JobRepository jobRepository, MongoItemReader<Person> mongoItemReader,
|
||||
MongoItemWriter<Person> mongoItemWriter) {
|
||||
return new StepBuilder("step").repository(jobRepository).<Person, Person>chunk(2).reader(mongoItemReader)
|
||||
.writer(mongoItemWriter).build();
|
||||
public Step step(JobRepository jobRepository, PlatformTransactionManager transactionManager,
|
||||
MongoItemReader<Person> mongoItemReader, MongoItemWriter<Person> mongoItemWriter) {
|
||||
return new StepBuilder("step", jobRepository).<Person, Person>chunk(2, transactionManager)
|
||||
.reader(mongoItemReader).writer(mongoItemWriter).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job insertionJob(JobRepository jobRepository, Step step) {
|
||||
return new JobBuilder("insertionJob").repository(jobRepository).start(step).build();
|
||||
return new JobBuilder("insertionJob", jobRepository).start(step).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
* Copyright 2020-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,10 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.MongoTransactionManager;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
|
||||
|
||||
@Configuration
|
||||
@PropertySource("classpath:/mongodb-sample.properties")
|
||||
@@ -38,10 +41,24 @@ public class MongoDBConfiguration {
|
||||
private String mongodbDatabase;
|
||||
|
||||
@Bean
|
||||
public MongoTemplate mongoTemplate() {
|
||||
public MongoClient mongoClient() {
|
||||
String connectionString = "mongodb://" + this.mongodbHost + ":" + this.mongodbPort + "/" + this.mongodbDatabase;
|
||||
MongoClient mongoClient = MongoClients.create(connectionString);
|
||||
return MongoClients.create(connectionString);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MongoTemplate mongoTemplate(MongoClient mongoClient) {
|
||||
return new MongoTemplate(mongoClient, "test");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MongoDatabaseFactory mongoDatabaseFactory(MongoClient mongoClient) {
|
||||
return new SimpleMongoClientDatabaseFactory(mongoClient, "test");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MongoTransactionManager transactionManager(MongoDatabaseFactory mongoDatabaseFactory) {
|
||||
return new MongoTransactionManager(mongoDatabaseFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ public class ManagerConfiguration {
|
||||
|
||||
@Bean
|
||||
public Job remoteChunkingJob(JobRepository jobRepository) {
|
||||
return new JobBuilder("remoteChunkingJob").repository(jobRepository).start(managerStep()).build();
|
||||
return new JobBuilder("remoteChunkingJob", jobRepository).start(managerStep()).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class ManagerConfiguration {
|
||||
|
||||
@Bean
|
||||
public Job remotePartitioningJob(JobRepository jobRepository) {
|
||||
return new JobBuilder("remotePartitioningJob").repository(jobRepository).start(managerStep()).build();
|
||||
return new JobBuilder("remotePartitioningJob", jobRepository).start(managerStep()).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public class WorkerConfiguration {
|
||||
@Bean
|
||||
public Step workerStep(PlatformTransactionManager transactionManager) {
|
||||
return this.workerStepBuilderFactory.get("workerStep").inputChannel(requests()).outputChannel(replies())
|
||||
.tasklet(tasklet(null)).transactionManager(transactionManager).build();
|
||||
.tasklet(tasklet(null), transactionManager).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -80,7 +80,7 @@ public class ManagerConfiguration {
|
||||
|
||||
@Bean
|
||||
public Job remotePartitioningJob(JobRepository jobRepository) {
|
||||
return new JobBuilder("remotePartitioningJob").repository(jobRepository).start(managerStep()).build();
|
||||
return new JobBuilder("remotePartitioningJob", jobRepository).start(managerStep()).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ public class WorkerConfiguration {
|
||||
*/
|
||||
@Bean
|
||||
public Step workerStep(PlatformTransactionManager transactionManager) {
|
||||
return this.workerStepBuilderFactory.get("workerStep").inputChannel(requests()).tasklet(tasklet(null))
|
||||
.transactionManager(transactionManager).build();
|
||||
return this.workerStepBuilderFactory.get("workerStep").inputChannel(requests())
|
||||
.tasklet(tasklet(null), transactionManager).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -83,14 +83,14 @@ public class SkippableExceptionDuringProcessSample {
|
||||
|
||||
@Bean
|
||||
public Step step(JobRepository jobRepository) {
|
||||
return new StepBuilder("step").repository(jobRepository).<Integer, Integer>chunk(3)
|
||||
.transactionManager(this.transactionManager).reader(itemReader()).processor(itemProcessor())
|
||||
.writer(itemWriter()).faultTolerant().skip(IllegalArgumentException.class).skipLimit(3).build();
|
||||
return new StepBuilder("step", jobRepository).<Integer, Integer>chunk(3, this.transactionManager)
|
||||
.reader(itemReader()).processor(itemProcessor()).writer(itemWriter()).faultTolerant()
|
||||
.skip(IllegalArgumentException.class).skipLimit(3).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job job(JobRepository jobRepository) {
|
||||
return new JobBuilder("job").repository(jobRepository).start(step(jobRepository)).build();
|
||||
return new JobBuilder("job", jobRepository).start(step(jobRepository)).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -83,14 +83,14 @@ public class SkippableExceptionDuringReadSample {
|
||||
|
||||
@Bean
|
||||
public Step step(JobRepository jobRepository) {
|
||||
return new StepBuilder("step").repository(jobRepository).<Integer, Integer>chunk(3)
|
||||
.transactionManager(this.transactionManager).reader(itemReader()).processor(itemProcessor())
|
||||
.writer(itemWriter()).faultTolerant().skip(IllegalArgumentException.class).skipLimit(3).build();
|
||||
return new StepBuilder("step", jobRepository).<Integer, Integer>chunk(3, this.transactionManager)
|
||||
.reader(itemReader()).processor(itemProcessor()).writer(itemWriter()).faultTolerant()
|
||||
.skip(IllegalArgumentException.class).skipLimit(3).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job job(JobRepository jobRepository) {
|
||||
return new JobBuilder("job").repository(jobRepository).start(step(jobRepository)).build();
|
||||
return new JobBuilder("job", jobRepository).start(step(jobRepository)).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -83,14 +83,14 @@ public class SkippableExceptionDuringWriteSample {
|
||||
|
||||
@Bean
|
||||
public Step step(JobRepository jobRepository) {
|
||||
return new StepBuilder("step").repository(jobRepository).<Integer, Integer>chunk(3)
|
||||
.transactionManager(this.transactionManager).reader(itemReader()).processor(itemProcessor())
|
||||
.writer(itemWriter()).faultTolerant().skip(IllegalArgumentException.class).skipLimit(3).build();
|
||||
return new StepBuilder("step", jobRepository).<Integer, Integer>chunk(3, this.transactionManager)
|
||||
.reader(itemReader()).processor(itemProcessor()).writer(itemWriter()).faultTolerant()
|
||||
.skip(IllegalArgumentException.class).skipLimit(3).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job job(JobRepository jobRepository) {
|
||||
return new JobBuilder("job").repository(jobRepository).start(step(jobRepository)).build();
|
||||
return new JobBuilder("job", jobRepository).start(step(jobRepository)).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,14 +66,13 @@ public class ValidationSampleConfiguration {
|
||||
|
||||
@Bean
|
||||
public Step step(JobRepository jobRepository) throws Exception {
|
||||
return new StepBuilder("step").repository(jobRepository).<Person, Person>chunk(1)
|
||||
.transactionManager(transactionManager(dataSource())).reader(itemReader()).processor(itemValidator())
|
||||
.writer(itemWriter()).build();
|
||||
return new StepBuilder("step", jobRepository).<Person, Person>chunk(1, transactionManager(dataSource()))
|
||||
.reader(itemReader()).processor(itemValidator()).writer(itemWriter()).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job job(JobRepository jobRepository) throws Exception {
|
||||
return new JobBuilder("job").repository(jobRepository).start(step(jobRepository)).build();
|
||||
return new JobBuilder("job", jobRepository).start(step(jobRepository)).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -90,14 +90,13 @@ class JsonSupportIntegrationTests {
|
||||
|
||||
@Bean
|
||||
public Step step(JobRepository jobRepository) {
|
||||
return new StepBuilder("step").repository(jobRepository).<Trade, Trade>chunk(2)
|
||||
.transactionManager(transactionManager(dataSource())).reader(itemReader()).writer(itemWriter())
|
||||
.build();
|
||||
return new StepBuilder("step", jobRepository).<Trade, Trade>chunk(2, transactionManager(dataSource()))
|
||||
.reader(itemReader()).writer(itemWriter()).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job job(JobRepository jobRepository) {
|
||||
return new JobBuilder("job").repository(jobRepository).start(step(jobRepository)).build();
|
||||
return new JobBuilder("job", jobRepository).start(step(jobRepository)).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
Reference in New Issue
Block a user