INT-4569: Disallow beans override in DSL (#2664)

* INT-4569: Disallow beans override in DSL

JIRA: https://jira.spring.io/browse/INT-4569

* Thorw `BeanDefinitionOverrideException` from the
`IntegrationFlowBeanPostProcessor` when it detects existing bean and it
is not the same object we try to register from the DSL
* Document limitations about `prototype` beans
* Some polishing in the DSL chapter of the docs

* * Fix algorithm in the `IntegrationFlowBeanPostProcessor.noBeanPresentForComponent()`

* * Polishing dsl.adoc
* Call `BeanFactory.initializeBean()` for existing beans if they are
`prototype`

* * Code formatting in the `ManualFlowTests`
This commit is contained in:
Artem Bilan
2018-12-18 14:22:17 -05:00
committed by Gary Russell
parent 65df35bfd1
commit 3dd8b63576
3 changed files with 86 additions and 23 deletions

View File

@@ -115,28 +115,38 @@ The endpoints are automatically wired together by using direct channels.
[[java-dsl-class-cast]]
.Lambdas And `Message<?>` Arguments
IMPORTANT: When using lambdas in EIP methods, the "input" argument is generally the message payload.
[IMPORTANT]
====
When using lambdas in EIP methods, the "input" argument is generally the message payload.
If you wish to access the entire message, use one of the overloaded methods that take a `Class<?>` as the first parameter.
For example, this won't work:
====
[source, java]
----
.<Message<?>, Foo>transform(m -> newFooFromMessage(m))
----
====
This will fail at runtime with a `ClassCastException` because the lambda doesn't retain the argument type and the framework will attempt to cast the payload to a `Message<?>`.
Instead, use:
====
[source, java]
----
.(Message.class, m -> newFooFromMessage(m))
----
====
[[bean-definitions-override]]
.Bean Definitions override
[IMPORTANT]
====
The Java DSL can register beans for the object defined in-line in the flow definition, as well as can reuse existing, injected beans.
In case of the same bean name defined for in-line object and existing bean definition, a `BeanDefinitionOverrideException` is thrown indicating that such a configuration is wrong.
However when you deal with `prototype` beans, there is no way to detect from the integration flow processor an existing bean definition because every time we call a `prototype` bean from the `BeanFactory` we get a new instance.
This way a provided instance is used in the `IntegrationFlow` as is without any bean registration and any possible check against existing `prototype` bean definition.
However `BeanFactory.initializeBean()` is called for this object if it has an explicit `id` and bean definition for this name is in `prototype` scope.
====
[[java-dsl-channels]]
=== Message Channels
@@ -316,7 +326,7 @@ It avoids inconvenient coding using setters and makes the flow definition more s
Note that you can use `Transformers` to declare target `Transformer` instances as `@Bean` instances and, again, use them from `IntegrationFlow` definition as bean methods.
Nevertheless, the DSL parser takes care of bean declarations for inline objects, if they are not yet defined as beans.
See [https://docs.spring.io/spring-integration/api/org/springframework/integration/dsl/Transformers.html] in the Javadoc for more information and supported factory methods.
See https://docs.spring.io/spring-integration/api/org/springframework/integration/dsl/Transformers.html[Transformers] in the Javadoc for more information and supported factory methods.
Also see <<java-dsl-class-cast>>.
@@ -789,15 +799,18 @@ public IntegrationFlow evenFlow() {
}
----
{empty} +
In this case, when you need to receive a reply from such a sub-flow and continue the main flow, this `IntegrationFlow` bean reference (or its input channel) has to be wrapped with a `.gateway()` as shown in the preceding example.
The `oddFlow()` reference in the preceding example is not wrapped to the `.gateway()`.
Therefore, we do not expect a reply from this routing branch.
Otherwise, you end up with an exception similar to the following:
[source]
----
Caused by: org.springframework.beans.factory.BeanCreationException: The 'currentComponent' (org.springframework.integration.router.MethodInvokingRouter@7965a51c) is a one-way 'MessageHandler' and it isn't appropriate to configure 'outputChannel'. This is the end of the integration flow.
----
....
Caused by: org.springframework.beans.factory.BeanCreationException:
The 'currentComponent' (org.springframework.integration.router.MethodInvokingRouter@7965a51c)
is a one-way 'MessageHandler' and it isn't appropriate to configure 'outputChannel'.
This is the end of the integration flow.
....
When you configure a sub-flow as a lambda, the framework handles the request-reply interaction with the sub-flow and a gateway is not needed.
====