Two years ago, I have written an article how to expose a local (service) method – given one object (request) as payload and one object as result (response). This article will be an updated method using Spring Integration Java DSL instead.
I know, you know, we are developers: Code says more than thousand words:
If you have read my article, you will probably notice it is actually the same piece of code. In the article of 2014, I have showed the configuration using XML.
Motivation: Java -> XML -> Java (again?)
In the last years, the benefit of using Integration Config with XML (instead of using Java Config) has been the existence of several configuration directives: in this case
<int:json-to-object-transformer> and several others. These directives controls the setup and will ensure all necessary beans are available and configured correctly. It is still Spring, so obviously everyone can reach the same goal building and configuring everything on his/her own needs. Unfortunately, these steps are quite complex, do have several implications and require configurations of objects you should even know about.
Simply: You are overwhelmed by configuring the technical details instead of concentrating of your actual taks. That is why the XML config variant (especially for Spring Integration) is much more better than JavaConfig: better to write, better to read.
It is actually the same with Spring Security: Although you can configure everything with standard JavaConfig, the configuration is much better to write and read using the XML directives.
However, even if you could put some dynamic in these more or less static XML configurations, a JavaConfig will be always much more dynamic because it is actual running code. That is why Spring Security Config exist, introduced in Spring Security 3.2 and 4 and shipped with class names mostly ending with Configurer (and convenient base classes to override). These are a bunch of shorthand, chained configuration objects controlling the little details. The result is a readable configuration – and it is more compact than the XML, too.
Welcome to Spring Integration DSL (Java)
I will concentrate on the Java part called Spring Integration Java DSL – but there are also projects for Groovy and Scala DSLs.
First of all: all concepts are the same, nothing has has changed. Probably you do not need to change any code of the connected services. But eventually you will optimize some pieces because of new possibilities (Java Lambas?).
The main sources for documentation are:
- Spring Integration Java DSL Documentation
- Line by Line tutorial
- and the samples at Dzone
Please be aware of some API changes between 1.0 and 1.1.
The most used entries will be probably:
- and several protocol specific adapters like:
Let’s start with the main flow using IntegrationFlows.
Remember, this is the original:
It actually had required 2*2 channels because of transforming objects. However, using the more elegant DSL it is simply this here (with the same result). The following is the complete configuration, only the AMQP setup is left.
It takes the messages of the AMQP queue named “queue”, puts them into an anonymous channel, transforms from JSON, handles calling the actual service, re-transforms back to JSON and finally replies back to the sender. No need for defining channels we actually do not care about.
As you can see, at this case there is actually no service activator required. Just a service like the others.
- Amqp.inboundGateway() returns the configurer/spec for the inbound adapter which can be configured additionally with more things, i.e. a dedicated TaskExecutor for blocking tasks or a specific errorChannel.
- The optional JsonObjectMapper is configured as a custom Jackson2 which let us control everything we want for JSON processing.
Note: Please be aware of the on demand creation of channels. See in the official document at “Message Channels” (end).
And the client?
Obviously, at this point, the application client also want to have such a nice configuration. The opposite for AMQP is – no surprise – Amqp.outboundGateway(). Let us put the pieces together.
Note: We are also using the channel names “requestChannel” and “resultChannel”, but you should be aware this are completely other channels on “client side” and “server side”!
Okay, we also have an integration flow.
As you can see, it basically only consumes all messages of the channel, transforms to JSON, handles via AMQP (which includes the reply handling), transforms the result back from JSON and returns the responses to the other channel. Just like in the first configuration we do not have to define the intermediate channels. We only have to decide whether it is a PubSub channel (if someone is pushing messages into it like a service or external adapter) or a direct channel (i.e. here for simple responses).
Given these both channels, we create a simple message gateway. Do not forget to include @IntegrationComponentScan when using the newer annotation @MessagingGateway.
Because the call will be asynchronously, it should be propably recommened to use a future result like
Just for the records: Of course I recommend using Java 8 with lambdas. Have fun!