diff --git a/spring-batch-docs/modules/ROOT/pages/step/controlling-flow.adoc b/spring-batch-docs/modules/ROOT/pages/step/controlling-flow.adoc
index 45aaa009b..7d3e70ab2 100644
--- a/spring-batch-docs/modules/ROOT/pages/step/controlling-flow.adoc
+++ b/spring-batch-docs/modules/ROOT/pages/step/controlling-flow.adoc
@@ -7,6 +7,21 @@ necessarily mean that the `Job` should fail. Furthermore, there may be more than
of "`success`" that determines which `Step` should be executed next. Depending upon how a
group of `Steps` is configured, certain steps may not even be processed at all.
+[IMPORTANT]
+.Step bean method proxying in flow definitions
+====
+A step instance must be unique within a flow definition. When a step has multiple outcomes in a flow definition,
+it is important that the same instance of the step is passed to the flow definition methods (`start`, `from`, etc).
+Otherwise, the flow execution might behave unexpectedly.
+
+In the following examples, steps are injected as parameters to the flow or job bean definition methods. This dependency injection style guarantees the uniqueness of steps in the flow definition.
+However, if the flow is defined by calling step definition methods annotated with `@Bean`, then steps might not be unique if bean method proxying is disabled (ie `@Configuration(proxyBeanMethods = false)`).
+If the inter-bean injection style is preferred, then bean method proxying must be enabled.
+
+Please refer to the https://docs.spring.io/spring-framework/reference/core/beans/java/configuration-annotation.html[Using the @Configuration annotation]
+section for more details about bean method proxying in Spring Framework.
+====
+
[[SequentialFlow]]
== Sequential Flow
@@ -29,11 +44,11 @@ The following example shows how to use the `next()` method in Java:
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, Step stepA, Step stepB, Step stepC) {
return new JobBuilder("job", jobRepository)
- .start(stepA())
- .next(stepB())
- .next(stepC())
+ .start(stepA)
+ .next(stepB)
+ .next(stepC)
.build();
}
----
@@ -95,11 +110,11 @@ proceed to either of two different steps (`stepB` or `stepC`), depending on whet
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, Step stepA, Step stepB, Step stepC) {
return new JobBuilder("job", jobRepository)
- .start(stepA())
- .on("*").to(stepB())
- .from(stepA()).on("FAILED").to(stepC())
+ .start(stepA)
+ .on("*").to(stepB)
+ .from(stepA).on("FAILED").to(stepC)
.end()
.build();
}
@@ -185,7 +200,7 @@ The following example contains the `on` element when using Java Configuration:
[source, java]
----
...
-.from(stepA()).on("FAILED").to(stepB())
+.from(stepA).on("FAILED").to(stepB)
...
----
@@ -239,11 +254,11 @@ The following example shows how to work with a different exit code in Java:
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, Step step1, Step step2, Step errorPrint1) {
return new JobBuilder("job", jobRepository)
- .start(step1()).on("FAILED").end()
- .from(step1()).on("COMPLETED WITH SKIPS").to(errorPrint1())
- .from(step1()).on("*").to(step2())
+ .start(step1).on("FAILED").end()
+ .from(step1).on("COMPLETED WITH SKIPS").to(errorPrint1)
+ .from(step1).on("*").to(step2)
.end()
.build();
}
@@ -319,9 +334,9 @@ In the following Java example, after the `step` executes, the `Job` ends:
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, Step step1) {
return new JobBuilder("job", jobRepository)
- .start(step1())
+ .start(step1)
.build();
}
----
@@ -332,7 +347,7 @@ In the following XML example, after the `step` executes, the `Job` ends:
+
[source, xml]
----
-
+
----
====
@@ -395,12 +410,12 @@ The following example shows the scenario in Java:
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, Step step1, Step step2, Step step3) {
return new JobBuilder("job", jobRepository)
- .start(step1())
- .next(step2())
+ .start(step1)
+ .next(step2)
.on("FAILED").end()
- .from(step2()).on("*").to(step3())
+ .from(step2).on("*").to(step3)
.end()
.build();
}
@@ -455,11 +470,11 @@ The following example shows the scenario in Java:
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, Step step1, Step step2, Step step3) {
return new JobBuilder("job", jobRepository)
- .start(step1())
- .next(step2()).on("FAILED").fail()
- .from(step2()).on("*").to(step3())
+ .start(step1)
+ .next(step2).on("FAILED").fail()
+ .from(step2).on("*").to(step3)
.end()
.build();
}
@@ -517,9 +532,9 @@ The following example shows the scenario in Java:
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, Step step1, Step step2) {
return new JobBuilder("job", jobRepository)
- .start(step1()).on("COMPLETED").stopAndRestart(step2())
+ .start(step1).on("COMPLETED").stopAndRestart(step2)
.end()
.build();
}
@@ -575,11 +590,11 @@ directly to the `next` call when using Java configuration:
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, MyDecider decider, Step step1, Step step2, Step step3) {
return new JobBuilder("job", jobRepository)
- .start(step1())
- .next(decider()).on("FAILED").to(step2())
- .from(decider()).on("COMPLETED").to(step3())
+ .start(step1)
+ .next(decider).on("FAILED").to(step2)
+ .from(decider).on("COMPLETED").to(step3)
.end()
.build();
}
@@ -633,27 +648,27 @@ previously discussed transition elements, such as the `next` attribute or the `n
[source, java]
----
@Bean
-public Flow flow1() {
+public Flow flow1(Step step1, Step step2) {
return new FlowBuilder("flow1")
- .start(step1())
- .next(step2())
+ .start(step1)
+ .next(step2)
.build();
}
@Bean
-public Flow flow2() {
+public Flow flow2(Step step3) {
return new FlowBuilder("flow2")
- .start(step3())
+ .start(step3)
.build();
}
@Bean
-public Job job(Flow flow1, Flow flow2) {
- return this.jobBuilderFactory.get("job")
+public Job job(JobRepository jobRepository, Flow flow1, Flow flow2, Step step4) {
+ return new JobBuilder("job", jobRepository)
.start(flow1)
.split(new SimpleAsyncTaskExecutor())
.add(flow2)
- .next(step4())
+ .next(step4)
.end()
.build();
}
@@ -699,23 +714,23 @@ Java::
The following Java example shows how to declare a flow as a reference to a flow defined
elsewhere:
+
-.Java Confguration
+.Java Configuration
[source, java]
----
@Bean
-public Job job(JobRepository jobRepository) {
+public Job job(JobRepository jobRepository, Flow flow1, Step step3) {
return new JobBuilder("job", jobRepository)
- .start(flow1())
- .next(step3())
+ .start(flow1)
+ .next(step3)
.end()
.build();
}
@Bean
-public Flow flow1() {
+public Flow flow1(Step step1, Step step2) {
return new FlowBuilder("flow1")
- .start(step1())
- .next(step2())
+ .start(step1)
+ .next(step2)
.build();
}
----
@@ -764,25 +779,25 @@ The following example shows an example of a `JobStep` in Java:
[source, java]
----
@Bean
-public Job jobStepJob(JobRepository jobRepository) {
+public Job jobStepJob(JobRepository jobRepository, Step jobStepJobStep1) {
return new JobBuilder("jobStepJob", jobRepository)
- .start(jobStepJobStep1(null))
+ .start(jobStepJobStep1)
.build();
}
@Bean
-public Step jobStepJobStep1(JobLauncher jobLauncher, JobRepository jobRepository) {
+public Step jobStepJobStep1(JobRepository jobRepository, JobLauncher jobLauncher, Job job, JobParametersExtractor jobParametersExtractor) {
return new StepBuilder("jobStepJobStep1", jobRepository)
- .job(job())
+ .job(job)
.launcher(jobLauncher)
- .parametersExtractor(jobParametersExtractor())
+ .parametersExtractor(jobParametersExtractor)
.build();
}
@Bean
public Job job(JobRepository jobRepository) {
return new JobBuilder("job", jobRepository)
- .start(step1())
+ // ...
.build();
}