INT-3534:MethodInvokingMLP Don't Copy Collection
JIRA: https://jira.spring.io/browse/INT-3534 Previously the `MethodInvokingMessageListProcessor` copied `Collection<Message<?>>` in its `process()` method for the `delegate` to a new `Collection` unconditionally. To improve performance, the collection is no longer copied unconditionally in the `ExpressionEvaluatingMessageGroupProcessor`. Also add an `important` note to the `aggregator.adoc` about the restriction with `unmodifiableCollection`.
This commit is contained in:
committed by
Gary Russell
parent
15e2187fd2
commit
51b161ae4d
@@ -18,14 +18,13 @@ package org.springframework.integration.aggregator;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.integration.util.AbstractExpressionEvaluator;
|
||||
import org.springframework.integration.util.MessagingMethodInvokerHelper;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
/**
|
||||
* A MessageListProcessor implementation that invokes a method on a target POJO.
|
||||
@@ -69,9 +68,9 @@ public class MethodInvokingMessageListProcessor<T> extends AbstractExpressionEva
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public T process(Collection<? extends Message<?>> messages, Map<String, Object> aggregateHeaders) {
|
||||
public T process(Collection<Message<?>> messages, Map<String, Object> aggregateHeaders) {
|
||||
try {
|
||||
return delegate.process(new ArrayList<Message<?>>(messages), aggregateHeaders);
|
||||
return delegate.process(messages, aggregateHeaders);
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw e;
|
||||
|
||||
@@ -104,9 +104,11 @@ However, there are better solutions, less coupled to the API, for implementing t
|
||||
In general, any POJO can implement the aggregation algorithm if it provides a method that accepts a single `java.util.List` as an argument (parameterized lists are supported as well).
|
||||
This method will be invoked for aggregating messages as follows:
|
||||
|
||||
* if the argument is a `java.util.List<T>`, and the parameter type T is assignable to `Message`, then the whole list of messages accumulated for aggregation will be sent to the aggregator
|
||||
* if the argument is a `java.util.Collection<T>`, and the parameter type T is assignable to `Message`,
|
||||
then the whole list of messages accumulated for aggregation will be sent to the aggregator
|
||||
|
||||
* if the argument is a non-parameterized `java.util.List` or the parameter type is not assignable to `Message`, then the method will receive the payloads of the accumulated messages
|
||||
* if the argument is a non-parameterized `java.util.Collection` or the parameter type is not assignable to `Message`,
|
||||
then the method will receive the payloads of the accumulated messages
|
||||
|
||||
* if the return type is not assignable to `Message`, then it will be treated as the payload for a Message that will be created automatically by the framework.
|
||||
|
||||
@@ -114,8 +116,20 @@ This method will be invoked for aggregating messages as follows:
|
||||
|
||||
NOTE: In the interest of code simplicity, and promoting best practices such as low coupling, testability, etc., the preferred way of implementing the aggregation logic is through a POJO, and using the XML or annotation support for configuring it in the application.
|
||||
|
||||
[[agg-message-collection]]
|
||||
IMPORTANT: The `SimpleMessageGroup.getMessages()` method returns an `unmodifiableCollection`, therefore,
|
||||
if your aggregating POJO method has a `Collection<Message>` parameter, the argument passed in will be exactly that
|
||||
`Collection` instance and, when a `SimpleMessageStore` is used for the Aggregator,
|
||||
that original `Collection<Message>` will be cleared after releasing the group.
|
||||
Hence the `Collection<Message>` variable in the POJO will be cleared too, if passed out of the aggregator.
|
||||
If you wish to simply release that collection as-is for further processing,
|
||||
it is required that you build a new `Collection` (e.g. `new ArrayList<Message>(messages)`)
|
||||
Starting with _version 4.3, the Framework no longer copies the messages to a new collection, to avoid undesired extra
|
||||
object creation.
|
||||
|
||||
|
||||
If the `MessageGroupProcessor` 's `processMessageGroup` method returns a collection, it must be a collection of
|
||||
`Messge<?>` s.
|
||||
`Message<?>` s.
|
||||
In this case, the messages are released individually.
|
||||
Prior to _version 4.2_, it was not possible to provide a `MessageGroupProcessor` using XML configuration, only POJO
|
||||
methods could be used for aggregation.
|
||||
|
||||
@@ -32,3 +32,9 @@ See <<imap-seen>> for more information.
|
||||
The `DefaultJmsHeaderMapper` now maps the standard `correlationId` header as a message property by invoking its
|
||||
`toString()` method.
|
||||
See <<jms-header-mapping>> for more information.
|
||||
|
||||
==== Aggregator Changes
|
||||
|
||||
There is a change in behavior when a POJO aggregator releases a collection of `Message<?>` objects; this is rare but if
|
||||
your application does that, you will need to make a small change to your POJO. See this <<agg-message-collection>> note
|
||||
for more information.
|
||||
|
||||
Reference in New Issue
Block a user