Update documentation

This commit is contained in:
Mahmoud Ben Hassine
2022-09-21 19:07:26 +02:00
parent 1141975470
commit 219fee3bad
10 changed files with 347 additions and 299 deletions

View File

@@ -74,8 +74,8 @@ The following example shows how to register a listener with a step Java:
[source, java, role="javaContent"]
----
@Bean
public Step simpleStep() {
return this.stepBuilderFactory.get("simpleStep")
public Step simpleStep(JobRepository jobRepository) {
return new StepBuilder("simpleStep", jobRepository)
...
.listener(new ItemFailureLoggerListener())
.build();
@@ -163,9 +163,9 @@ The following example shows how to inject a completion policy into a step in Jav
[source, java, role="javaContent"]
----
@Bean
public Step simpleStep() {
return this.stepBuilderFactory.get("simpleStep")
.<String, String>chunk(new SpecialCompletionPolicy())
public Step simpleStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("simpleStep", jobRepository)
.<String, String>chunk(new SpecialCompletionPolicy(), transactionManager)
.reader(reader())
.writer(writer())
.build();
@@ -724,17 +724,17 @@ The following example shows how to promote a step to the `Job` `ExecutionContext
[source, java, role="javaContent"]
----
@Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
public Job job1(JobRepository jobRepository) {
return new JobBuilder("job1", jobRepository)
.start(step1())
.next(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(10)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(reader())
.writer(savingWriter())
.listener(promotionListener())

View File

@@ -72,8 +72,8 @@ example shows:
[source, java, role="javaContent"]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
@@ -111,8 +111,8 @@ instantiation of a `Job`, as the following example shows:
[source, java]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())

View File

@@ -36,8 +36,8 @@ The following example creates a `footballJob`:
[source, java, role="javaContent"]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
@@ -106,8 +106,8 @@ namespace (for XML-based configuration). The following example shows both Java a
[source, java]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
@@ -184,8 +184,8 @@ The following example shows how to set the `restartable` field to `false` in Jav
[source, java, role="javaContent"]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.preventRestart()
...
.build();
@@ -274,8 +274,8 @@ The following example shows how to add a listener method to a Java job definitio
[source, java, role="javaContent"]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.listener(sampleListener())
...
.build();
@@ -390,8 +390,8 @@ The configuration of a validator is supported through the Java builders:
[source, java, role="javaContent"]
----
@Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
public Job job1(JobRepository jobRepository) {
return new JobBuilder("job1", jobRepository)
.validator(parametersValidator())
...
.build();
@@ -408,8 +408,8 @@ The configuration of a validator is supported through the Java builders, as foll
[source, java]
----
@Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
public Job job1(JobRepository jobRepository) {
return tnew JobBuilder("job1", jobRepository)
.validator(parametersValidator())
...
.build();
@@ -444,37 +444,46 @@ annotation and two builders.
The `@EnableBatchProcessing` annotation works similarly to the other `@Enable*` annotations in the
Spring family. In this case, `@EnableBatchProcessing` provides a base configuration for
building batch jobs. Within this base configuration, an instance of `StepScope` is
building batch jobs. Within this base configuration, an instance of `StepScope` and `Jobscope` are
created, in addition to a number of beans being made available to be autowired:
* `JobRepository`: a bean named `jobRepository`
* `JobLauncher`: a bean named `jobLauncher`
* `JobRegistry`: a bean named `jobRegistry`
* `PlatformTransactionManager`: a bean named `transactionManager`
* `JobBuilderFactory`: a bean named `jobBuilders`
* `StepBuilderFactory`: a bean named `stepBuilders`
* `JobExplorer`: a bean named `jobExplorer`
The core interface for this configuration is the `BatchConfigurer`. The default
implementation provides the beans mentioned in the preceding list and requires a `DataSource`
to be provided as a bean within the context. This data source is used by the `JobRepository` instance.
You can customize any of these beans
by creating a custom implementation of the `BatchConfigurer` interface.
Typically, extending the `DefaultBatchConfigurer` (which is provided if a
`BatchConfigurer` is not found) and overriding the required getter is sufficient.
However, you may need to implement your own from scratch. The following
example shows how to provide a custom transaction manager:
The default implementation provides the beans mentioned in the preceding list and requires a `DataSource`
and a `PlatformTransactionManager` to be provided as beans within the context. The data source and transaction
manager are used by the `JobRepository` and `JobExplorer` instances. By default, the data source named `dataSource`
and the transaction manager named `transactionManager` will be used. You can customize any of these beans by using
the attributes of the `@EnableBatchProcessing` annotation. The following example shows how to provide a
custom data source and transaction manager:
====
[source, java]
----
@Bean
public BatchConfigurer batchConfigurer(DataSource dataSource) {
return new DefaultBatchConfigurer(dataSource) {
@Override
public PlatformTransactionManager getTransactionManager() {
return new MyTransactionManager();
}
};
@Configuration
@EnableBatchProcessing(dataSourceRef = "batchDataSource", transactionManagerRef = "batchTransactionManager")
public class MyJobConfiguration {
@Bean
public DataSource batchDataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
.addScript("/org/springframework/batch/core/schema-hsqldb.sql")
.generateUniqueName(true).build();
}
@Bean
public JdbcTransactionManager batchTransactionManager(DataSource dataSource) {
return new JdbcTransactionManager(dataSource);
}
public Job job(JobRepository jobRepository) {
return new JobBuilder("myJob", jobRepository)
//define job flow as needed
.build();
}
}
----
====
@@ -485,51 +494,62 @@ Only one configuration class needs to have the `@EnableBatchProcessing` annotati
you have a class annotated with it, you have all of the configuration described earlier.
====
With the base configuration in place, you can use the provided builder factories to
configure a job. The following example shows a two-step job configured with the
`JobBuilderFactory` and the `StepBuilderFactory`:
Starting from v5.0, an alternative, programmatic way of configuring base infrastrucutre beans
is provided through the `DefaultBatchConfiguration` class. This class provides the same beans
provided by `@EnableBatchProcessing` and can be used as a base class to configure batch jobs.
The following snippet is a typical example of how to use it:
====
[source, java]
----
@Configuration
@EnableBatchProcessing
@Import(DataSourceConfiguration.class)
public class AppConfig {
class MyJobConfiguration extends DefaultBatchConfiguration {
@Autowired
private JobBuilderFactory jobs;
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// define job flow as needed
.build();
}
@Autowired
private StepBuilderFactory steps;
@Bean
public Job job(@Qualifier("step1") Step step1, @Qualifier("step2") Step step2) {
return jobs.get("myJob").start(step1).next(step2).build();
}
@Bean
protected Step step1(ItemReader<Person> reader,
ItemProcessor<Person, Person> processor,
ItemWriter<Person> writer) {
return steps.get("step1")
.<Person, Person> chunk(10)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
@Bean
protected Step step2(Tasklet tasklet) {
return steps.get("step2")
.tasklet(tasklet)
.build();
}
}
----
====
The data source and transaction manager will be resolved from the application context
and set on the job repository and job explorer. You can customize the configuration
of any infrastructure bean by overriding the required setter. The following example
shows how to customize the character encoding for instance:
====
[source, java]
----
@Configuration
class MyJobConfiguration extends DefaultBatchConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// define job flow as needed
.build();
}
@Override
protected Charset getCharset() {
return StandardCharsets.ISO_8859_1;
}
}
----
====
[NOTE]
====
`@EnableBatchProcessing` should *not* be used with `DefaultBatchConfiguration`. You should
either use the declarative way of configuring Spring Batch through `@EnableBatchProcessing`,
or use the programmatic way of extending `DefaultBatchConfiguration`, but not both ways at
the same time.
====
[[configuringJobRepository]]
=== Configuring a JobRepository
@@ -538,10 +558,8 @@ When using `@EnableBatchProcessing`, a `JobRepository` is provided for you.
This section describes how to configure your own.
As described earlier, the <<job.adoc#configureJob,`JobRepository`>> is used for basic CRUD operations of the various persisted
domain objects within Spring Batch, such as
`JobExecution` and
`StepExecution`. It is required by many of the major
framework features, such as the `JobLauncher`,
domain objects within Spring Batch, such as `JobExecution` and `StepExecution`.
It is required by many of the major framework features, such as the `JobLauncher`,
`Job`, and `Step`.
[role="xmlContent"]
@@ -569,32 +587,6 @@ The `max-varchar-length` defaults to `2500`, which is the length of the long
`VARCHAR` columns in the <<schema-appendix.adoc#metaDataSchemaOverview,sample schema
scripts>>.
[role="javaContent"]
When you use Java configuration, a `JobRepository` is provided for you. A JDBC-based one is
provided if a `DataSource` is provided, and the `Map`-based one is provided if no `DataSource` is provided. However,
you can customize the configuration of the `JobRepository` through an implementation of the
`BatchConfigurer` interface, as the following example shows:
.Java Configuration
====
[source, java, role="javaContent"]
----
...
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setIsolationLevelForCreate("ISOLATION_SERIALIZABLE");
factory.setTablePrefix("BATCH_");
factory.setMaxVarCharLength(1000);
return factory.getObject();
}
...
----
====
[role="javaContent"]
Other than the `dataSource` and the `transactionManager`, none of the configuration options listed earlier are required.
If they are not set, the defaults shown earlier
@@ -637,19 +629,17 @@ The following example shows how to override the isolation level in Java:
====
[source, java, role="javaContent"]
----
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setIsolationLevelForCreate("ISOLATION_REPEATABLE_READ");
return factory.getObject();
@Configuration
@EnableBatchProcessing(isolationLevelForCreate = "ISOLATION_REPEATABLE_READ")
public class MyJobConfiguration {
// job definition
}
----
====
If the namespace or factory beans are not used, you must also configure the
If the namespace is not used, you must also configure the
transactional behavior of the repository by using AOP.
[role="xmlContent"]
@@ -727,14 +717,12 @@ The following example shows how to change the table prefix in Java:
====
[source, java, role="javaContent"]
----
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setTablePrefix("SYSTEM.TEST_");
return factory.getObject();
@Configuration
@EnableBatchProcessing(tablePrefix = "SYSTEM.TEST_")
public class MyJobConfiguration {
// job definition
}
----
====
@@ -778,9 +766,8 @@ to the closest match in Java:
====
[source, java, role="javaContent"]
----
// This would reside in your BatchConfigurer implementation
@Override
protected JobRepository createJobRepository() throws Exception {
@Bean
public JobRepository jobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setDatabaseType("db2");
@@ -835,9 +822,8 @@ The following example shows a `TaskExecutorJobLauncher` in Java:
[source, java, role="javaContent"]
----
...
// This would reside in your BatchConfigurer implementation
@Override
protected JobLauncher createJobLauncher() throws Exception {
@Bean
public JobLauncher jobLauncher() throws Exception {
TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
jobLauncher.setJobRepository(jobRepository);
jobLauncher.afterPropertiesSet();
@@ -1057,23 +1043,17 @@ The following example shows a sample configuration for `endOfDay` in Java:
@EnableBatchProcessing
public class EndOfDayJobConfiguration {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job endOfDay() {
return this.jobBuilderFactory.get("endOfDay")
.start(step1())
public Job endOfDay(JobRepository jobRepository, Step step1) {
return new JobBuilder("endOfDay", jobRepository)
.start(step1)
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.tasklet((contribution, chunkContext) -> null)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet((contribution, chunkContext) -> null, transactionManager)
.build();
}
}
@@ -1120,25 +1100,19 @@ The following example shows a sample configuration for `endOfDay` in Java:
@EnableBatchProcessing
public class EndOfDayJobConfiguration {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job endOfDay(JobRepository jobRepository, Step step1) {
return new JobBuilder("endOfDay", jobRepository)
.start(step1)
.build();
}
@Bean
public Job endOfDay() {
return this.jobBuilderFactory.get("endOfDay")
.start(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.tasklet((contribution, chunkContext) -> null)
.build();
}
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet((contribution, chunkContext) -> null, transactionManager)
.build();
}
}
----
====
@@ -1738,8 +1712,8 @@ For jobs defined in Java, you can associate an incrementer with a `Job` through
[source, java, role="javaContent"]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.incrementer(sampleIncrementer())
...
.build();
@@ -1768,8 +1742,8 @@ The Java configuration builders also provide facilities for the configuration of
[source, java]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.incrementer(sampleIncrementer())
...
.build();

View File

@@ -107,16 +107,16 @@ objects, throwing an exception if any other type is provided. Similarly, the
[source, java, role="javaContent"]
----
@Bean
public Job ioSampleJob() {
return this.jobBuilderFactory.get("ioSampleJob")
public Job ioSampleJob(JobRepository jobRepository) {
return new JobBuilder("ioSampleJob", jobRepository)
.start(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<Foo, Bar>chunk(2)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.<Foo, Bar>chunk(2, transactionManager)
.reader(fooReader())
.processor(fooProcessor())
.writer(barWriter())
@@ -212,16 +212,16 @@ Just as with the previous example, you can configure the composite processor int
[source, java, role="javaContent"]
----
@Bean
public Job ioSampleJob() {
return this.jobBuilderFactory.get("ioSampleJob")
public Job ioSampleJob(JobRepository jobRepository) {
return new JobBuilder("ioSampleJob", jobRepository)
.start(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<Foo, Foobar>chunk(2)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<Foo, Foobar>chunk(2, transactionManager)
.reader(fooReader())
.processor(compositeProcessor())
.writer(foobarWriter())

View File

@@ -175,16 +175,16 @@ The following example shows how to inject a delegate as a stream in XML:
[source, java, role="javaContent"]
----
@Bean
public Job ioSampleJob() {
return this.jobBuilderFactory.get("ioSampleJob")
public Job ioSampleJob(JobRepository jobRepository) {
return new JobBuilder("ioSampleJob", jobRepository)
.start(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(2)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.<String, String>chunk(2, transactionManager)
.reader(fooReader())
.processor(fooProcessor())
.writer(compositeItemWriter())

View File

@@ -62,9 +62,9 @@ public TaskExecutor taskExecutor() {
}
@Bean
public Step sampleStep(TaskExecutor taskExecutor) {
return this.stepBuilderFactory.get("sampleStep")
.<String, String>chunk(10)
public Step sampleStep(TaskExecutor taskExecutor, JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("sampleStep", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.taskExecutor(taskExecutor)
@@ -106,9 +106,9 @@ follows:
[source, java, role="javaContent"]
----
@Bean
public Step sampleStep(TaskExecutor taskExecutor) {
return this.stepBuilderFactory.get("sampleStep")
.<String, String>chunk(10)
public Step sampleStep(TaskExecutor taskExecutor, JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("sampleStep", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.taskExecutor(taskExecutor)
@@ -179,8 +179,8 @@ is straightforward, as follows:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(splitFlow())
.next(step4())
.build() //builds FlowJobBuilder instance

View File

@@ -520,8 +520,8 @@ The following example shows the how to add a step-level listener in Java:
.Java Configuration
[source, java, role="javaContent"]
----
public Job importPaymentsJob() {
return jobBuilderFactory.get("importPayments")
public Job importPaymentsJob(JobRepository jobRepository) {
return new JobBuilder("importPayments", jobRepository)
.start(stepBuilderFactory.get("step1")
.chunk(200)
.listener(notificationExecutionsListener())
@@ -673,8 +673,8 @@ following in Java:
.Java Configuration
[source, java, role="javaContent"]
----
public Job chunkJob() {
return jobBuilderFactory.get("personJob")
public Job chunkJob(JobRepository jobRepository) {
return new JobBuilder("personJob", jobRepository)
.start(stepBuilderFactory.get("step1")
.<Person, Person>chunk(200)
.reader(itemReader())
@@ -1230,8 +1230,8 @@ Java:
.Java Configuration
[source, java, role="javaContent"]
----
public Job personJob() {
return jobBuilderFactory.get("personJob")
public Job personJob(JobRepository jobRepository) {
return new JobBuilder("personJob", jobRepository)
.start(stepBuilderFactory.get("step1.manager")
.partitioner("step1.worker", partitioner())
.partitionHandler(partitionHandler())

View File

@@ -120,8 +120,7 @@ following example shows:
*/
@Bean
public Job sampleJob(JobRepository jobRepository, Step sampleStep) {
return this.jobBuilderFactory.get("sampleJob")
.repository(jobRepository)
return new JobBuilder("sampleJob", jobRepository)
.start(sampleStep)
.build();
}
@@ -131,10 +130,9 @@ public Job sampleJob(JobRepository jobRepository, Step sampleStep) {
* configured
*/
@Bean
public Step sampleStep(PlatformTransactionManager transactionManager) {
return this.stepBuilderFactory.get("sampleStep")
.transactionManager(transactionManager)
.<String, String>chunk(10)
public Step sampleStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("sampleStep", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.build();
@@ -182,9 +180,9 @@ Note that `job-repository` defaults to `jobRepository` and
optional, since the item could be directly passed from the reader to the writer.
[role="javaContent"]
Note that `repository` defaults to `jobRepository` and `transactionManager`
defaults to `transactionManager` (all provided through the infrastructure from
`@EnableBatchProcessing`). Also, the `ItemProcessor` is optional, since the item could be
Note that `repository` defaults to `jobRepository` (provided through `@EnableBatchProcessing`)
and `transactionManager` defaults to `transactionManager` (provided from the application context).
Also, the `ItemProcessor` is optional, since the item could be
directly passed from the reader to the writer.
endif::backend-html5[]
@@ -354,16 +352,16 @@ value of 10 as it would be defined in Java:
[source, java, role="javaContent"]
----
@Bean
public Job sampleJob() {
return this.jobBuilderFactory.get("sampleJob")
public Job sampleJob(JobRepository jobRepository) {
return new JobBuilder("sampleJob", jobRepository)
.start(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(10)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.build();
@@ -412,9 +410,9 @@ The following code fragment shows an example of a start limit configuration in J
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(10)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.startLimit(1)
@@ -456,9 +454,9 @@ The following code fragment shows how to define a restartable job in Java:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(10)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.allowStartIfComplete(true)
@@ -506,8 +504,8 @@ restarted:
[source, java, role="javaContent"]
----
@Bean
public Job footballJob() {
return this.jobBuilderFactory.get("footballJob")
public Job footballJob(JobRepository jobRepository) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad())
.next(gameLoad())
.next(playerSummarization())
@@ -515,29 +513,29 @@ public Job footballJob() {
}
@Bean
public Step playerLoad() {
return this.stepBuilderFactory.get("playerLoad")
.<String, String>chunk(10)
public Step playerLoad(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("playerLoad", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(playerFileItemReader())
.writer(playerWriter())
.build();
}
@Bean
public Step gameLoad() {
return this.stepBuilderFactory.get("gameLoad")
public Step gameLoad(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("gameLoad", jobRepository)
.allowStartIfComplete(true)
.<String, String>chunk(10)
.<String, String>chunk(10, transactionManager)
.reader(gameFileItemReader())
.writer(gameWriter())
.build();
}
@Bean
public Step playerSummarization() {
return this.stepBuilderFactory.get("playerSummarization")
public Step playerSummarization(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("playerSummarization", jobRepository)
.startLimit(2)
.<String, String>chunk(10)
.<String, String>chunk(10, transactionManager)
.reader(playerSummarizationSource())
.writer(summaryWriter())
.build();
@@ -635,9 +633,9 @@ The following Java example shows an example of using a skip limit:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(10)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(flatFileItemReader())
.writer(itemWriter())
.faultTolerant()
@@ -687,9 +685,9 @@ The following Java example shows an example excluding a particular exception:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(10)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(flatFileItemReader())
.writer(itemWriter())
.faultTolerant()
@@ -755,9 +753,9 @@ In Java, retry should be configured as follows:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(2)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(2, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.faultTolerant()
@@ -805,9 +803,9 @@ In Java, you can control rollback as follows:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(2)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(2, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.faultTolerant()
@@ -848,9 +846,9 @@ The following example shows how to create a reader that does not buffer items in
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(2)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(2, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.readerIsTransactionalQueue()
@@ -892,14 +890,14 @@ attributes in Java:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
attribute.setPropagationBehavior(Propagation.REQUIRED.value());
attribute.setIsolationLevel(Isolation.DEFAULT.value());
attribute.setTimeout(30);
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(2)
return new StepBuilder("step1", jobRepository)
.<String, String>chunk(2, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.transactionAttribute(attribute)
@@ -957,9 +955,9 @@ The following example shows how to register a `stream` on a `step` in Java:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(2)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(2, transactionManager)
.reader(itemReader())
.writer(compositeItemWriter())
.stream(fileItemWriter1())
@@ -1031,9 +1029,9 @@ The following example shows a listener applied at the chunk level in Java:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<String, String>chunk(10)
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return tnew StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(reader())
.writer(writer())
.listener(chunkListener())
@@ -1285,9 +1283,9 @@ building a `TaskletStep`. The following example shows a simple tasklet:
[source, java, role="javaContent"]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.tasklet(myTasklet())
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet(myTasklet(), transactionManager)
.build();
}
----
@@ -1311,9 +1309,9 @@ simple `tasklet`:
[source, java]
----
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.tasklet(myTasklet())
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet(myTasklet(), transactionManager)
.build();
}
----
@@ -1438,16 +1436,16 @@ The following example shows how to reference the `tasklet` from the `step` in Ja
[source, java, role="javaContent"]
----
@Bean
public Job taskletJob() {
return this.jobBuilderFactory.get("taskletJob")
public Job taskletJob(JobRepository jobRepository) {
return new JobBuilder("taskletJob", jobRepository)
.start(deleteFilesInDir())
.build();
}
@Bean
public Step deleteFilesInDir() {
return this.stepBuilderFactory.get("deleteFilesInDir")
.tasklet(fileDeletingTasklet())
public Step deleteFilesInDir(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("deleteFilesInDir", jobRepository)
.tasklet(fileDeletingTasklet(), transactionManager)
.build();
}
@@ -1501,8 +1499,8 @@ The following example shows how to use the `next()` method in Java:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(stepA())
.next(stepB())
.next(stepC())
@@ -1573,8 +1571,8 @@ proceed to either of two different steps (`stepB` or `stepC`), depending on whet
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(stepA())
.on("*").to(stepB())
.from(stepA()).on("FAILED").to(stepC())
@@ -1675,8 +1673,8 @@ The following example shows how to work with a different exit code in Java:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(step1()).on("FAILED").end()
.from(step1()).on("COMPLETED WITH SKIPS").to(errorPrint1())
.from(step1()).on("*").to(step2())
@@ -1741,8 +1739,8 @@ In the following Java example, after the `step` executes, the `Job` ends:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(step1())
.build();
}
@@ -1811,8 +1809,8 @@ The following example shows the scenario in Java:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(step1())
.next(step2())
.on("FAILED").end()
@@ -1863,8 +1861,8 @@ The following example shows the scenario in Java:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(step1())
.next(step2()).on("FAILED").fail()
.from(step2()).on("*").to(step3())
@@ -1909,8 +1907,8 @@ The following example shows the scenario in Java:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(step1()).on("COMPLETED").stopAndRestart(step2())
.end()
.build();
@@ -1970,8 +1968,8 @@ directly to the `next` call when using Java configuration:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(step1())
.next(decider()).on("FAILED").to(step2())
.from(decider()).on("COMPLETED").to(step3())
@@ -2076,8 +2074,8 @@ elsewhere:
[source, java, role="javaContent"]
----
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(flow1())
.next(step3())
.end()
@@ -2130,15 +2128,15 @@ The following example shows an example of a `JobStep` in Java:
[source, java, role="javaContent"]
----
@Bean
public Job jobStepJob() {
return this.jobBuilderFactory.get("jobStepJob")
public Job jobStepJob(JobRepository jobRepository) {
return new JobBuilder("jobStepJob", jobRepository)
.start(jobStepJobStep1(null))
.build();
}
@Bean
public Step jobStepJobStep1(JobLauncher jobLauncher) {
return this.stepBuilderFactory.get("jobStepJobStep1")
public Step jobStepJobStep1(JobLauncher jobLauncher, JobRepository jobRepository) {
return new StepBuilder("jobStepJobStep1", jobRepository)
.job(job())
.launcher(jobLauncher)
.parametersExtractor(jobParametersExtractor())
@@ -2146,8 +2144,8 @@ public Step jobStepJobStep1(JobLauncher jobLauncher) {
}
@Bean
public Job job() {
return this.jobBuilderFactory.get("job")
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
.start(step1())
.build();
}

View File

@@ -47,20 +47,22 @@ This release also marks the migration to:
Spring Batch 5 includes the following infrastructure configuration updates:
* <<datasource-requirement-updates>>
* <<datasource-transaction-manager-requirement-updates>>
* <<transaction-manager-bean-exposure>>
* <<default-transaction-manager-type>>
* <<new-attributes-enable-batch-processing>>
* <<new-configuration-class>>
* <<transaction-support-in-job-explorer-and-job-operator>>
[[datasource-requirement-updates]]
==== DataSource Requirement Updates
[[datasource-transaction-manager-requirement-updates]]
==== Data Source and Transaction manager Requirement Updates
Historically, Spring Batch provided a map-based job repository and job explorer implementations to work with
an in-memory job repository. These implementations were deprecated in version 4 and completely removed in version 5.
The recommended replacement is to use the JDBC-based implementations with an embedded database, such as H2, HSQL, and others.
In this release, the `@EnableBatchProcessing` annotation configures a JDBC-based `JobRepository`, which requires a
`DataSource` bean in the application context. The `DataSource` bean could refer to an embedded database to work with
an in-memory job repository.
`DataSource` and `PlatformTransactionManager` beans to be defined in the application context. The `DataSource` bean
could refer to an embedded database to work with an in-memory job repository.
[[transaction-manager-bean-exposure]]
==== Transaction Manager Bean Exposure
@@ -70,13 +72,87 @@ context. While this was convenient in many cases, the unconditional exposure of
interfere with a user-defined transaction manager. In this release, `@EnableBatchProcessing` no longer exposes a
transaction manager bean in the application context.
[[default-transaction-manager-type]]
==== Default Transaction Manager Type
[[new-attributes-enable-batch-processing]]
==== New annotation attributes in EnableBatchProcessing
When no transaction manager is specified, `@EnableBatchProcessing` used (up to version 4.3) to register a default
transaction manager of type `org.springframework.jdbc.datasource.DataSourceTransactionManager` in the proxy around
`JobRepository` when a `DataSource` bean is defined in the application context. In this release, the type of the
default transaction manager has changed to `org.springframework.jdbc.support.JdbcTransactionManager`.
In this release, the `@EnableBatchProcessing` annotation provides new attributes to specify which
components and parameters should be used to configure the Batch infrastructure beans. For example,
it is now possible to specify which data source and transaction manager Spring Batch should configure
in the job repository as follows:
```
@Configuration
@EnableBatchProcessing(dataSourceRef = "batchDataSource", transactionManagerRef = "batchTransactionManager")
public class MyJobConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("myJob", jobRepository)
//define job flow as needed
.build();
}
}
```
In this example, `batchDataSource` and `batchTransactionManager` refer to beans in the application context,
and which will be used to configure the job repository and job explorer. There is no need to define a
custom `BatchConfiguer` anymore, which was removed in this release.
[[new-configuration-class]]
==== New configuration class for infrastructure beans
In this release, a new configuration class named `DefaultBatchConfiguration` can be used as an alternative to
using `@EnableBatchProcessing` for the configuration of infrastrucutre beans. This class provides infrastructure
beans with default configuration which can be customized as needed. The following snippet shows a typical usage
of this class:
```
@Configuration
class MyJobConfiguration extends DefaultBatchConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("myJob", jobRepository)
//define job flow as needed
.build();
}
}
```
In this example, the `JobRepository` bean injected in the `Job` bean definition is defined in the `DefaultBatchConfiguration`
class. Custom parameters can be specified by overriding the corresponding getter. For example, the following example shows
how to override the default character encoding used in the job repository and job explorer:
```
@Configuration
class MyJobConfiguration extends DefaultBatchConfiguration {
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
// define job flow as needed
.build();
}
@Override
protected Charset getCharset() {
return StandardCharsets.ISO_8859_1;
}
}
```
[[transaction-support-in-job-explorer-and-job-operator]]
=== Transaction support in JobExplorer and JobOperator
This release introduces transaction support in the `JobExplorer` created through
the `JobExplorerFactoryBean`. It is now possible to specify which transaction manager
to use to drive the ready-only transactions when querying the Batch meta-data as well as
customizing the transaction attributes.
The same transaction support was added to the `JobOperator` through a new factory bean
named `JobOperatorFactoryBean`.
[[batch-testing-configuration-updates]]
=== Batch Testing Configuration Updates