The goal for this article: expose a method of a bean via AMQP and use JSON as a unified transport which can be serialized and deserialized in every language (and forget the xml overhead, of course).
- All examples are cleaned up and being reduced of irrelevant boiler code like for demo-purpose unnecessary xml headers.
Let’s start with an implementation:
Both Request and Response are good old plain Java objects with can easy serialized and deserialized. Excited about Joda? I’ve written something about it!
If we want to expose that one, we first have to connect this with Spring Integration. Speaking of Spring Integration, that means basically connecting something (i.e. a method) with a channel which is the instrument of message flows in Integration. Well, that means actually integrating stuff. Not a freely chosen name? 🙂
For configuration purpose, you can use both JavaConfig and XML. However, while JavaConfig is more confidently usable with parameters, especially the Integration configuration is sometimes more readable in XML. Chose your own way, but be consistent. Mixing up configurations is a no-brainer.
First of all, we have to define two channels. One for incoming messages (the actual argument of the method invocation), another one for outgoing messages (the return value).
Because we want to invoke a service on a message, we simply use a ServiceActivator. For each message in the requestChannel, it will be invoked.
So far, each message in requestChannel will be an invocation of ApiImpl. The additions in the class defines which method should be invoked and which message argument should be extracted from the payload (you could use the actual Integration Message object, but we stick with the payload). The return result will be pushed wrapped into a message again into the defined output channel resultChannel.
The method is now well “integrated”.
Said this, we want to connect the channels with an AMQP server in order to handle incoming requests and process them. Then plan is simple: For each message at a specific queue, we create a message and put it into a channel and wait for a corresponding reply message on another channel to make a real “reply behavior”. The whole stuff is already implemented and built-in available in Spring Integration AMQP.
For example, you have a queue named queue (hell, yes).
And that.. that was it? Well, actually we have reached the goal of connection already. We have defined an inbound gateway (read: get all messages and put them into a channel and do this for the returning result vice versa) and connect all channels. Basically, this works. However, this means that the message’s payload will be transmitted with a standard serializer and deserializer which means Java Object serializing. That is not good between different components or even the non Java world.
Solving this issue means introducing some neat transformers. A transformer is nothing less than a mapper converting objects from one type to another. In our case, we want to transport the objects via JSON. So: Read JSON from AMQP, deserialize it back to a POJO, process the message, return a value and serialize it to JSON and finally send it back via AMQP.
We add two more channels which are being the new connection points for the AMQP endpoint: both requestChannelJson and resultChannelJson will be feeded with JSON messages.
As you see, the built-in directives defines that all messages of requestChannelJson will be transformed to a POJO and put into requestChannel. The same way back for the result channels. Finally, we have to adjust the AMQP configuration to use the new Json channels. That’s it.