Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immutable message in Spring Integration

I was wondering what is the reasoning behind making messages immutable in Spring Integration.

Is it only because of thread-safety in multi threaded evnironments?

Performance? Don't you get a performance penalization when you have to create a new message each time you want to add something to an existing message?

Avoiding a range of bugs when passing by reference? Just guessing here.

like image 521
souser Avatar asked Jan 09 '18 08:01

souser


1 Answers

The simplest way to explain this comes from the original Java Immutable Objects idea:

Immutable objects are particularly useful in concurrent applications. Since they cannot change state, they cannot be corrupted by thread interference or observed in an inconsistent state.

Since we talk here about Messaging we should always keep in mind the Loose coupling principle where the producer (caller) and consumer (executor) know nothing about each other and they communicate only via messages (events, commands, packages etc.). At the same time the same message may have several consumers to perform absolutely not related business logics. So, supporting immutable state for the active object we don't impact one process from another. That's might be also as a part of the security between processes when we execute a message in isolation.

The Spring Integration is really pure Java, so any concurrency and security restrictions just simply applied here as well and you would be surprised distributing a message to different independent processes and see modifications from one process in the other.

There is some information in the Reference Manual:

Therefore, when a Message instance is sent to multiple consumers (e.g. through a Publish Subscribe Channel), if one of those consumers needs to send a reply with a different payload type, it will need to create a new Message. As a result, the other consumers are not affected by those changes.

As you see it is applied for Message object per se and its MessageHeaders. The payload is fully your responsibility and I really had in past some problems adding and removing elements to the ArrayList payload in multi-threaded business logic.

Anyway the Framework suggest a compromise: MutableMessage, MutableMessageHeaders and MutableMessageBuilder. You also can globally override the MessageBuilder used in the Framework internally to the MutableMessageBuilderFactory. For this purpose you just need to register such a bean with the bean name IntegrationUtils.INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME:

@Bean(name = IntegrationUtils.INTEGRATION_MESSAGE_BUILDER_FACTORY_BEAN_NAME)
public static MessageBuilderFactory mutableMessageBuilderFactory() {
    return new MutableMessageBuilderFactory();
}

And all messages in your integration flows will be mutable and supply the same id and timestamp headers.

like image 116
Artem Bilan Avatar answered Sep 29 '22 09:09

Artem Bilan