I was wondering if it is possible in Spring AMQP to receive messages from the same queue in multiple classes depending on the payload type.
I am aware of using the @RabbitListener annotation in class and then putting @RabbitHandler on methods, but I would like to split complexity of message handling in multiple classes while keeping a single queue.
Version currently in use: Spring AMQP v2.0.3 along with RabbitMQ.
Well, it isn't possible. The way you would like it won't be a queue then.
That is really an architecture decision to design a single listener and distribute to its methods according the payload type.
As a workaround I can suggest you to delegate the logic from a single @RabbitListener class to those business services:
@RabbitListener(queues = "foo")
public class MyListener {
private final ServiceA serviceA;
private final ServiceB serviceB;
public MyListener(ServiceA serviceA, ServiceB serviceB) {
this.serviceA = serviceA;
this.serviceB = serviceB;
}
@RabbitHandler
public void handleA(A a) {
this.serviceA.handle(a);
}
@RabbitHandler
public void handleB(B b) {
this.serviceB.handle(b);
}
}
Yes you can, but it takes a little different approach: You need lo listen to the generic Message Type, do some switching, and your own deserialisation. You can of course completly hide that code somewhere (baseclass, annotations...)
Example below can be extended to listen to whatever types extra. The example above would be to filter on A and B DTO types.
void receive(ADTO dto)
{
System.out.print(dto.url);
}
void receive(BDTO dto)
{
System.out.print(dto.url);
}
@RabbitListener(queues = "your.queue.name")
public void listenMesssage(Message message)
{
try
{
String typeId = message.getMessageProperties().getHeaders().get("__TypeId__").toString();
String contentType = message.getMessageProperties().getContentType();
if (contentType != "application/json" || typeId == null || !typeId.contains(ADTO.class.toString()))
{
//TODO log warning
System.out.print("type not supported by this service");
return;
}
Object receivedObject = new Jackson2JsonMessageConverter().fromMessage(message);
if (receivedObject instanceof ADTO)
{
receive((ADTO)receivedObject);
System.out.print("ADTO");
}
//else
Alternatively, you can also do the serialisation like this:
....
String typeId = message.getMessageProperties().getHeaders().get("__TypeId__").toString();
byte[] binMsg = message.getBody();
String strMsg = new String(binMsg, StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
if (typeId.contains("ADTO"))
{
receive(mapper.readValue(strMsg, ADTO.class ));
}
else
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With