diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java index bafe56a48..c32ffd1ce 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultBatchConfiguration.java @@ -81,7 +81,7 @@ import org.springframework.transaction.annotation.Isolation; * *
  * @Configuration
- * public class MyJobConfiguration extends AbstractBatchConfiguration {
+ * public class MyJobConfiguration extends DefaultBatchConfiguration {
  *
  *    @Bean
  *    public Job job(JobRepository jobRepository) {
diff --git a/spring-batch-docs/src/main/asciidoc/common-patterns.adoc b/spring-batch-docs/src/main/asciidoc/common-patterns.adoc
index f59e840bd..9a32e0517 100644
--- a/spring-batch-docs/src/main/asciidoc/common-patterns.adoc
+++ b/spring-batch-docs/src/main/asciidoc/common-patterns.adoc
@@ -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")
-				.chunk(new SpecialCompletionPolicy())
+public Step simpleStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return new StepBuilder("simpleStep", jobRepository)
+				.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")
-				.chunk(10)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.chunk(10, transactionManager)
 				.reader(reader())
 				.writer(savingWriter())
 				.listener(promotionListener())
diff --git a/spring-batch-docs/src/main/asciidoc/domain.adoc b/spring-batch-docs/src/main/asciidoc/domain.adoc
index c22589d6a..faf9f372b 100644
--- a/spring-batch-docs/src/main/asciidoc/domain.adoc
+++ b/spring-batch-docs/src/main/asciidoc/domain.adoc
@@ -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())
diff --git a/spring-batch-docs/src/main/asciidoc/job.adoc b/spring-batch-docs/src/main/asciidoc/job.adoc
index d0df6f64a..5f39d69eb 100644
--- a/spring-batch-docs/src/main/asciidoc/job.adoc
+++ b/spring-batch-docs/src/main/asciidoc/job.adoc
@@ -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 reader,
-                         ItemProcessor processor,
-                         ItemWriter writer) {
-        return steps.get("step1")
-            . 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 <> 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 <>.
 
-[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();
diff --git a/spring-batch-docs/src/main/asciidoc/processor.adoc b/spring-batch-docs/src/main/asciidoc/processor.adoc
index c4e08f1fd..fcf6608f0 100644
--- a/spring-batch-docs/src/main/asciidoc/processor.adoc
+++ b/spring-batch-docs/src/main/asciidoc/processor.adoc
@@ -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")
-				.chunk(2)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return new StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(2)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.chunk(2, transactionManager)
 				.reader(fooReader())
 				.processor(compositeProcessor())
 				.writer(foobarWriter())
diff --git a/spring-batch-docs/src/main/asciidoc/readersAndWriters.adoc b/spring-batch-docs/src/main/asciidoc/readersAndWriters.adoc
index d2d0cbceb..e49b95f69 100644
--- a/spring-batch-docs/src/main/asciidoc/readersAndWriters.adoc
+++ b/spring-batch-docs/src/main/asciidoc/readersAndWriters.adoc
@@ -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")
-				.chunk(2)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return new StepBuilder("step1", jobRepository)
+				.chunk(2, transactionManager)
 				.reader(fooReader())
 				.processor(fooProcessor())
 				.writer(compositeItemWriter())
diff --git a/spring-batch-docs/src/main/asciidoc/scalability.adoc b/spring-batch-docs/src/main/asciidoc/scalability.adoc
index 14d7157a6..f3f1b4e61 100644
--- a/spring-batch-docs/src/main/asciidoc/scalability.adoc
+++ b/spring-batch-docs/src/main/asciidoc/scalability.adoc
@@ -62,9 +62,9 @@ public TaskExecutor taskExecutor() {
 }
 
 @Bean
-public Step sampleStep(TaskExecutor taskExecutor) {
-	return this.stepBuilderFactory.get("sampleStep")
-				.chunk(10)
+public Step sampleStep(TaskExecutor taskExecutor, JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return new StepBuilder("sampleStep", jobRepository)
+				.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")
-				.chunk(10)
+public Step sampleStep(TaskExecutor taskExecutor, JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return new StepBuilder("sampleStep", jobRepository)
+				.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
diff --git a/spring-batch-docs/src/main/asciidoc/spring-batch-integration.adoc b/spring-batch-docs/src/main/asciidoc/spring-batch-integration.adoc
index b3a409192..acee4b961 100644
--- a/spring-batch-docs/src/main/asciidoc/spring-batch-integration.adoc
+++ b/spring-batch-docs/src/main/asciidoc/spring-batch-integration.adoc
@@ -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")
                      .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())
diff --git a/spring-batch-docs/src/main/asciidoc/step.adoc b/spring-batch-docs/src/main/asciidoc/step.adoc
index fd4462721..acd229813 100644
--- a/spring-batch-docs/src/main/asciidoc/step.adoc
+++ b/spring-batch-docs/src/main/asciidoc/step.adoc
@@ -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)
-				.chunk(10)
+public Step sampleStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return new StepBuilder("sampleStep", jobRepository)
+				.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")
-				.chunk(10)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(10)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(10)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-			.chunk(10)
+public Step playerLoad(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return new StepBuilder("playerLoad", jobRepository)
+			.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)
-			.chunk(10)
+			.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)
-			.chunk(10)
+			.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")
-				.chunk(10)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(10)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(2)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(2)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(2)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(2)
+	return new StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(2)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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")
-				.chunk(10)
+public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
+	return tnew StepBuilder("step1", jobRepository)
+				.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();
 }
diff --git a/spring-batch-docs/src/main/asciidoc/whatsnew.adoc b/spring-batch-docs/src/main/asciidoc/whatsnew.adoc
index d85e7492f..f21a17b33 100644
--- a/spring-batch-docs/src/main/asciidoc/whatsnew.adoc
+++ b/spring-batch-docs/src/main/asciidoc/whatsnew.adoc
@@ -47,20 +47,22 @@ This release also marks the migration to:
 
 Spring Batch 5 includes the following infrastructure configuration updates:
 
-* <>
+* <>
 * <>
-* <>
+* <>
+* <>
+* <>
 
-[[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