How to build a nonblocking Consumer when using AsyncRabbitTemplate with Request/Reply Pattern - spring

I'm new to rabbitmq and currently trying to implement a nonblocking producer with a nonblocking consumer. I've build some test producer where I played around with typereference:
#Service
public class Producer {
#Autowired
private AsyncRabbitTemplate asyncRabbitTemplate;
public <T extends RequestEvent<S>, S> RabbitConverterFuture<S> asyncSendEventAndReceive(final T event) {
return asyncRabbitTemplate.convertSendAndReceiveAsType(QueueConfig.EXCHANGE_NAME, event.getRoutingKey(), event, event.getResponseTypeReference());
}
}
And in some other place the test function that gets called in a RestController
#Autowired
Producer producer;
public void test() throws InterruptedException, ExecutionException {
TestEvent requestEvent = new TestEvent("SOMEDATA");
RabbitConverterFuture<TestResponse> reply = producer.asyncSendEventAndReceive(requestEvent);
log.info("Hello! The Reply is: {}", reply.get());
}
This so far was pretty straightforward, where I'm stuck now is how to create a consumer which is non-blocking too. My current listener:
#RabbitListener(queues = QueueConfig.QUEUENAME)
public TestResponse onReceive(TestEvent event) {
Future<TestResponse> replyLater = proccessDataLater(event.getSomeData())
return replyLater.get();
}
As far as I'm aware, when using #RabbitListener this listener runs in its own thread. And I could configure the MessageListener to use more then one thread for the active listeners. Because of that, blocking the listener thread with future.get() is not blocking the application itself. Still there might be the case where all threads are blocking now and new events are stuck in the queue, when they maybe dont need to. What I would like to do is to just receive the event without the need to instantly return the result. Which is probably not possible with #RabbitListener. Something like:
#RabbitListener(queues = QueueConfig.QUEUENAME)
public void onReceive(TestEvent event) {
/*
* Some fictional RabbitMQ API call where i get a ReplyContainer which contains
* the CorrelationID for the event. I can call replyContainer.reply(testResponse) later
* in the code without blocking the listener thread
*/
ReplyContainer replyContainer = AsyncRabbitTemplate.getReplyContainer()
// ProcessDataLater calls reply on the container when done with its action
proccessDataLater(event.getSomeData(), replyContainer);
}
What is the best way to implement such behaviour with rabbitmq in spring?
EDIT Config Class:
#Configuration
#EnableRabbit
public class RabbitMQConfig implements RabbitListenerConfigurer {
public static final String topicExchangeName = "exchange";
#Bean
TopicExchange exchange() {
return new TopicExchange(topicExchangeName);
}
#Bean
public ConnectionFactory rabbitConnectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost("localhost");
return connectionFactory;
}
#Bean
public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
return new MappingJackson2MessageConverter();
}
#Bean
public RabbitTemplate rabbitTemplate() {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory());
rabbitTemplate.setMessageConverter(producerJackson2MessageConverter());
return rabbitTemplate;
}
#Bean
public AsyncRabbitTemplate asyncRabbitTemplate() {
return new AsyncRabbitTemplate(rabbitTemplate());
}
#Bean
public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
return new Jackson2JsonMessageConverter();
}
#Bean
Queue queue() {
return new Queue("test", false);
}
#Bean
Binding binding() {
return BindingBuilder.bind(queue()).to(exchange()).with("foo.#");
}
#Bean
public SimpleRabbitListenerContainerFactory myRabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(rabbitConnectionFactory());
factory.setMaxConcurrentConsumers(5);
factory.setMessageConverter(producerJackson2MessageConverter());
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return factory;
}
#Override
public void configureRabbitListeners(final RabbitListenerEndpointRegistrar registrar) {
registrar.setContainerFactory(myRabbitListenerContainerFactory());
}
}

I don't have time to test it right now, but something like this should work; presumably you don't want to lose messages so you need to set the ackMode to MANUAL and do the acks yourself (as shown).
UPDATE
#SpringBootApplication
public class So52173111Application {
private final ExecutorService exec = Executors.newCachedThreadPool();
#Autowired
private RabbitTemplate template;
#Bean
public ApplicationRunner runner(AsyncRabbitTemplate asyncTemplate) {
return args -> {
RabbitConverterFuture<Object> future = asyncTemplate.convertSendAndReceive("foo", "test");
future.addCallback(r -> {
System.out.println("Reply: " + r);
}, t -> {
t.printStackTrace();
});
};
}
#Bean
public AsyncRabbitTemplate asyncTemplate(RabbitTemplate template) {
return new AsyncRabbitTemplate(template);
}
#RabbitListener(queues = "foo")
public void listen(String in, Channel channel, #Header(AmqpHeaders.DELIVERY_TAG) long tag,
#Header(AmqpHeaders.CORRELATION_ID) String correlationId,
#Header(AmqpHeaders.REPLY_TO) String replyTo) {
ListenableFuture<String> future = handleInput(in);
future.addCallback(result -> {
Address address = new Address(replyTo);
this.template.convertAndSend(address.getExchangeName(), address.getRoutingKey(), result, m -> {
m.getMessageProperties().setCorrelationId(correlationId);
return m;
});
try {
channel.basicAck(tag, false);
}
catch (IOException e) {
e.printStackTrace();
}
}, t -> {
t.printStackTrace();
});
}
private ListenableFuture<String> handleInput(String in) {
SettableListenableFuture<String> future = new SettableListenableFuture<String>();
exec.execute(() -> {
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
future.set(in.toUpperCase());
});
return future;
}
public static void main(String[] args) {
SpringApplication.run(So52173111Application.class, args);
}
}

Related

Spring Boot RabbitMQ ConnectException:

I have an application that should work with rabbitmq. I have RabbitMQConfig, which tries to connect with the rabbit, but if it fails to connect, the application does not start at all.
What I want to achieve is that after launching the application, it will try to connect to the rabbit and if it manages to connect, I will start functionality to create a queue and listen to it accordingly. Currently at startup if the rabbit is available and then disappears it starts throwing "java.net.ConnectException: Connection refused". Can I catch this error and how, both at startup and during the operation of the application.
This is config file:
public class RabbitMQConfig implements RabbitListenerConfigurer {
private ConnectionFactory connectionFactory;
#Autowired
public RabbitMQConfig(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
#Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory());
}
#Bean
MessageHandlerMethodFactory messageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory messageHandlerMethodFactory = new DefaultMessageHandlerMethodFactory();
messageHandlerMethodFactory.setMessageConverter(consumerJackson2MessageConverter());
return messageHandlerMethodFactory;
}
#Bean
public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
return new MappingJackson2MessageConverter();
}
#Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
return rabbitTemplate;
}
#Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(connectionFactory);
}
#Bean(name = "rabbitListenerContainerFactory")
public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer,
ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
FixedBackOff recoveryBackOff = new FixedBackOff(10000,FixedBackOff.UNLIMITED_ATTEMPTS);
factory.setRecoveryBackOff(recoveryBackOff);
configurer.configure(factory, connectionFactory);
return factory;
}
Whit this methods i create and start listener:
#Service
public class RabbitMQService {
#RabbitListener(queues = "${queueName}", autoStartup = "false", id = "commandQueue")
public void receive(CommandDataDTO commandDataDTO) {
public void receive(Object rMessage) {
doSomething(rMessage);
}
public void createQueue() {
Queue queue = new Queue("queueName"), true, false, false);
Binding binding = new Binding("queueName"),
Binding.DestinationType.QUEUE, env.getProperty("spring.rabbitmq.exchange"),"rKey",
null);
admin.declareQueue(queue);
admin.declareBinding(binding);
startListener();
}
//When queue is active we start Listener
public void startListener() {
boolean isQueuqReady = false;
while (!isQueuqReady) {
Properties p = admin.getQueueProperties(env.getProperty("management.registry.info.device-type") + "_"
+ env.getProperty("management.registry.info.device-specific-type"));
if (p != null) {
log.info("Rabbit queue is up. Start listener.");
isQueuqReady = true;
registry.getListenerContainer("commandQueue").start();
}
}
}
Problem is that I want, regardless of whether there is a connection or not with the rabbit, the application to be able to work and, accordingly, to intercept when there is a connection and when not to do different actions.

RabbitMQ message not being sent to Dead Letter Queue on Exception

I have this RabbitMQ Spring Boot Configuration:
#Configuration
public class RabbitConfiguration {
// Main queue configuration
#Value("${rabbitmq.main.messages.queue}")
private String mainQueueName;
#Value("${rabbitmq.main.exchange.queue}")
private String mainExchangeName;
#Value("${rabbitmq.main.routing.key}")
private String mainRoutingKey;
// DLQ configuration
#Value("${rabbitmq.dlq.messages.queue}")
private String dlqQueueName;
#Value("${rabbitmq.dlq.exchange.queue}")
private String dlqExchangeName;
#Value("${rabbitmq.dlq.routing.key}")
private String dlqRoutingKey;
// Connectivity
#Value("${spring.rabbitmq.host}")
private String rabbitmqHost;
#Value("${spring.rabbitmq.port}")
private int rabbitmqPort;
#Value("${spring.rabbitmq.username}")
private String rabbitmqUsername;
#Value("${spring.rabbitmq.password}")
private String rabbitmqPassword;
// Not delivered messages, will be used eventually
#Value("${rabbitmq.not.delivered.messages.queue}")
private String notDeliveredMessagesQueue;
// status with delivered messages (callback default)
#Value("${rabbitmq.delivered.messages.queue}")
private String deliveredMessagesQueue;
#Bean
DirectExchange deadLetterExchange() {
return new DirectExchange(dlqExchangeName);
}
#Bean
DirectExchange exchange() {
return new DirectExchange(mainExchangeName);
}
#Bean
Queue dlq() {
return QueueBuilder.durable(dlqQueueName).build();
}
#Bean
Queue queue() {
return QueueBuilder
.durable(mainQueueName)
.withArgument("x-dead-letter-exchange", "deadLetterExchange")
.withArgument("x-dead-letter-routing-key", dlqQueueName).build();
}
#Bean
Binding deadLetterBinding() {
return BindingBuilder.bind(dlq()).to(deadLetterExchange()).with(dlqRoutingKey);
}
#Bean
Binding binding() {
return BindingBuilder.bind(queue()).to(exchange()).with(mainQueueName);
}
#Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(rabbitmqHost);
connectionFactory.setUsername(rabbitmqUsername);
connectionFactory.setPassword(rabbitmqPassword);
return connectionFactory;
}
#Bean
public RabbitAdmin rabbitAdmin() {
RabbitAdmin admin = new RabbitAdmin(connectionFactory());
admin.declareQueue(queue());
admin.declareExchange(exchange());
admin.declareBinding(binding());
return admin;
}
public AmqpTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}
}
The problem is that when some exception is launched the message is not sent to DLQ queue.
Consumer:
#RabbitListener(queues = { "${rabbitmq.main.messages.queue}" })
public void recievedMessage(#Payload Mensagem item, Channel channel, #Header(AmqpHeaders.DELIVERY_TAG) long tag) throws InvalidMessageException {
if (item.getIdCliente().equals("69")) {
logger.info("Something went wrong to: " + item);
throw new InvalidMessageException();
} else {
logger.info("==> Message consumed successfully: " + item);
}
}
This is the configuration I have on my application.properties:
spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.initial-interval=3s
spring.rabbitmq.listener.simple.retry.max-attempts=2
spring.rabbitmq.listener.simple.retry.multiplier=2
spring.rabbitmq.listener.simple.retry.max-interval=10s
When I throw an exception on purpose just to see the message moving to DLQ nothing happens. What's wrong here? What am I forgetting here?
Try adding
spring.rabbitmq.listener.simple.default-requeue-rejected=false
to your application.properties. I think the problem is that the failed deliveries are being requeued instead of being sent to the DLQ.

How to configure spring integration adapters of a merely connecting client and a server sending messages

I'm trying to implement the following scenario using Spring Integration:
I need a client to connect to a server via TCP IP and wait to receive messages within 30 seconds.
I need a server to send 0 to n messages to the client which had connected.
I need a way to start and stop channel transfer without loss of messages.
I need to change the port the server is listening between stop and start.
This is my config so far:
#Configuration
public class TcpConfiguration {
private static Logger LOG = LoggerFactory.getLogger(TcpConfiguration.class);
#Value("${port}")
private Integer port;
#Value("${so-timeout}")
private Integer soTimeout;
#Value("${keep-alive}")
private Boolean keepAlive;
#Value("${send-timeout}")
private Integer sendTimeout;
#Bean
public AbstractServerConnectionFactory getMyConnFactory() {
LOG.debug("getMyConnFactory");
TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(port);
LOG.debug("getMyConnFactory port={}", port);
factory.setSoTimeout(soTimeout);
LOG.debug("getMyConnFactory soTimeout={}", soTimeout);
factory.setSoKeepAlive(true);
LOG.debug("getMyConnFactory keepAlive={}", keepAlive);
return factory;
}
#Bean
public AbstractEndpoint getMyChannelAdapter() {
LOG.debug("getMyChannelAdapter");
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(getMyConnFactory());
adapter.setOutputChannel(myChannelIn());
adapter.setSendTimeout(sendTimeout);
LOG.debug("getMyChannelAdapter adapter={}", adapter.getClass().getName());
return adapter;
}
#Bean
public MessageChannel myChannelIn() {
LOG.debug("myChannelIn");
return new DirectChannel();
}
#Bean
#Transformer(inputChannel = "myChannelIn", outputChannel = "myServiceChannel")
public ObjectToStringTransformer myTransformer() {
LOG.debug("myTransformer");
return new ObjectToStringTransformer();
}
#ServiceActivator(inputChannel = "myServiceChannel")
public void service(String in) {
LOG.debug("service received={}", in);
}
#Bean
public MessageChannel myChannelOut() {
LOG.debug("myChannelOut");
return new DirectChannel();
}
#Bean
public IntegrationFlow myOutbound() {
LOG.debug("myOutbound");
return IntegrationFlows.from(myChannelOut())
.handle(mySender())
.get();
}
#Bean
public MessageHandler mySender() {
LOG.debug("mySender");
TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
tcpSendingMessageHandler.setConnectionFactory(getMyConnFactory());
return tcpSendingMessageHandler;
}
}
Please advice!
To change the server port I would shutdown the application context and restart it after configuring the new port in a remote configuration server.
Can I just close the application context without corrupting the current message transfer?
I don't know how to handle the connect-only client thing.
Use dynamic flow registration; just get the connection to open it without sending.
#SpringBootApplication
public class So62867670Application {
public static void main(String[] args) {
SpringApplication.run(So62867670Application.class, args);
}
#Bean
public ApplicationRunner runner(DynamicTcpReceiver receiver) {
return args -> { // Just a demo to show starting/stopping
receiver.connectAndListen(1234);
System.in.read();
receiver.stop();
System.in.read();
receiver.connectAndListen(1235);
System.in.read();
receiver.stop();
};
}
}
#Component
class DynamicTcpReceiver {
#Autowired
private IntegrationFlowContext context;
private IntegrationFlowRegistration registration;
public void connectAndListen(int port) throws InterruptedException {
TcpClientConnectionFactorySpec client = Tcp.netClient("localhost", port)
.deserializer(TcpCodecs.lf());
IntegrationFlow flow = IntegrationFlows.from(Tcp.inboundAdapter(client))
.transform(Transformers.objectToString())
.handle(System.out::println)
.get();
this.registration = context.registration(flow).register();
client.get().getConnection(); // just open the single shared connection
}
public void stop() {
if (this.registration != null) {
this.registration.destroy();
this.registration = null;
}
}
}
EDIT
And this is the server side...
#SpringBootApplication
#EnableScheduling
public class So62867670ServerApplication {
public static void main(String[] args) {
SpringApplication.run(So62867670ServerApplication.class, args);
}
#Bean
public ApplicationRunner runner(DynamicTcpServer receiver) {
return args -> { // Just a demo to show starting/stopping
receiver.tcpListen(1234);
System.in.read();
receiver.stop(1234);
System.in.read();
receiver.tcpListen(1235);
System.in.read();
receiver.stop(1235);
};
}
}
#Component
class DynamicTcpServer {
private static final Logger LOG = LoggerFactory.getLogger(DynamicTcpServer.class);
#Autowired
private IntegrationFlowContext flowContext;
#Autowired
private ApplicationContext appContext;
private final Map<Integer, IntegrationFlowRegistration> registrations = new HashMap<>();
private final Map<String, Entry<Integer, AtomicInteger>> clients = new ConcurrentHashMap<>();
public void tcpListen(int port) {
TcpServerConnectionFactorySpec server = Tcp.netServer(port)
.id("server-" + port)
.serializer(TcpCodecs.lf());
server.get().registerListener(msg -> false); // dummy listener so the accept thread doesn't exit
IntegrationFlow flow = f -> f.handle(Tcp.outboundAdapter(server));
this.registrations.put(port, flowContext.registration(flow).register());
}
public void stop(int port) {
IntegrationFlowRegistration registration = this.registrations.remove(port);
if (registration != null) {
registration.destroy();
}
}
#EventListener
public void closed(TcpConnectionOpenEvent event) {
LOG.info(event.toString());
String connectionId = event.getConnectionId();
String[] split = connectionId.split(":");
int port = Integer.parseInt(split[2]);
this.clients.put(connectionId, new AbstractMap.SimpleEntry<>(port, new AtomicInteger()));
}
#EventListener
public void closed(TcpConnectionCloseEvent event) {
LOG.info(event.toString());
this.clients.remove(event.getConnectionId());
}
#EventListener
public void listening(TcpConnectionServerListeningEvent event) {
LOG.info(event.toString());
}
#Scheduled(fixedDelay = 5000)
public void sender() {
this.clients.forEach((connectionId, portAndCount) -> {
IntegrationFlowRegistration registration = this.registrations.get(portAndCount.getKey());
if (registration != null) {
LOG.info("Sending to " + connectionId);
registration.getMessagingTemplate().send(MessageBuilder.withPayload("foo")
.setHeader(IpHeaders.CONNECTION_ID, connectionId).build());
if (portAndCount.getValue().incrementAndGet() > 9) {
this.appContext.getBean("server-" + portAndCount.getKey(), TcpNetServerConnectionFactory.class)
.closeConnection(connectionId);
}
}
});
}
}

Springboot RabbitMq Consumer consuming only at first time.please help me to get the configurations right and how can configure multiple listners

Springboot RabbitMq Consumer consuming only at first time.please help me to get the configurations right and how can configure multiple listners.I am developing an Automated Mapping solution for which i Execute various jobs .and in a need to put those jobs in queue
Here's my application class:Application.java
#SpringBootApplication
#ComponentScan(basePackages = { "com.fractal.sago", "com.fractal.grpc" })
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
RabbitMqConfig class:
#Configuration
public class RabbitMqConfig {
public final static String JOB_QUEUE_NAME = "jobQueue";
public final static String JOB_EXCHANGE_NAME = "jobExchange";
#Bean
Queue jobQueue() {
return new Queue(JOB_QUEUE_NAME, true);
}
#Bean
DirectExchange jobExchange() {
return new DirectExchange(JOB_EXCHANGE_NAME);
}
#Bean
Binding jobBinding(DirectExchange directExchange) {
return BindingBuilder.bind(jobQueue()).to(jobExchange()).with(jobQueue().getName());
}
#Bean
SimpleMessageListenerContainer jobQueueContainer(ConnectionFactory connectionFactory,
MessageListenerAdapter joblistenerAdapter) {
SimpleMessageListenerContainer jobQueueContainer = new SimpleMessageListenerContainer();
jobQueueContainer.setConnectionFactory(connectionFactory);
jobQueueContainer.setQueueNames(JOB_QUEUE_NAME);
jobQueueContainer.setMessageListener(joblistenerAdapter);
return jobQueueContainer;
}
#Bean
MessageListenerAdapter joblistenerAdapter(JobQueueConsumer messageReceiver) {
MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(messageReceiver, "receiveMessage");
messageListenerAdapter.setMessageConverter(producerJackson2MessageConverter());
return messageListenerAdapter;
}
#Bean
public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
return new Jackson2JsonMessageConverter();
}
}
producer : JobProducer
#Component
public class JobQueueProducer {
#Autowired
RabbitTemplate rabbitTemplate;
public void sendMessage(String message) {
Message messageToSend = MessageBuilder.withBody(message.getBytes())
.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
rabbitTemplate.convertAndSend(RabbitMqConfig.JOB_EXCHANGE_NAME, RabbitMqConfig.JOB_QUEUE_NAME, messageToSend);
//rabbitTemplate.convertAndSend(RabbitMqConfig.JOB_QUEUE_NAME, messageToSend);
}
}
Consumer :JobQueueConsumer
enter code here
#Component
public class JobQueueConsumer implements MessageListener {
#Autowired
SagoAlgo sagoAlgo;
#Autowired
CCDMappingService ccdMappingService;
#RabbitListener(queues = { RabbitMqConfig.JOB_QUEUE_NAME })
public void receiveMessage(Message message) throws SQLException {
System.out.println("Received Message: " + new String(message.getBody()));
Integer jobId = Integer.parseInt(new String(message.getBody()));
System.out.println(jobId);
CCDMappingVO ccdVo =ccdMappingService.fetchCCDWithCategoriesById(jobId);
sagoAlgo.execAlgo(ccdVo); //my Algo to be executed
}
//when I implement MessageListener default method to be executed
public void onMessage(Message message) {
// System.out.println("Received Message: " + new
// String(message.getBody()));
}
}

Spring Rabbit MQ Publish and Acknowledge

In my project i am having 3 Classes App(Publisher), PojoListener(Receiver) , Config(bind both App and PojoListner). But i need to separate out the PojoListener from my project and deploy somewhere else so that my Listener class will continuous listen to the Rabbit Mq and ack the messages back to queue and then to App Class for any messages published by my App class.
As my config file is common for both Publisher and Receiver. Is there any way to seperate out them. I need to deploy my receiver on different server and Publisher on different. Both will listen to common queues.
**App.java** :
public class App {
public static void main(String[] args) throws UnsupportedEncodingException {
ApplicationContext context = new AnnotationConfigApplicationContext(RabbitMQConfig.class);
RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
String response = (String) rabbitTemplate.convertSendAndReceive("message from publisher");
System.out.println("message sent");
System.out.println("response from :" + response);
}
}
PojoListener.java :
public class PojoListener {
public String handleMessage(String msg) {
System.out.println("IN POJO RECEIVER!!!");
return msg.toUpperCase();
}
}
RabbitMQConfig.java :
#Configuration
public class RabbitMQConfig {
#Bean
public ConnectionFactory rabbitConnectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
return connectionFactory;
}
#Bean
public RabbitTemplate fixedReplyQRabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(rabbitConnectionFactory());
template.setExchange(ex().getName());
template.setRoutingKey("test");
template.setReplyQueue(replyQueue());
template.setReplyTimeout(60000);
return template;
}
#Bean
public SimpleMessageListenerContainer replyListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(rabbitConnectionFactory());
container.setQueues(replyQueue());
container.setMessageListener(fixedReplyQRabbitTemplate());
return container;
}
#Bean
public SimpleMessageListenerContainer serviceListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(rabbitConnectionFactory());
container.setQueues(requestQueue());
container.setMessageListener(new MessageListenerAdapter(new PojoListener()));
return container;
}
#Bean
public DirectExchange ex() {
return new DirectExchange("rabbit-exchange", false, true);
}
#Bean
public Binding binding() {
return BindingBuilder.bind(requestQueue()).to(ex()).with("test");
}
#Bean
public Queue requestQueue() {
return new Queue("request-queue-spring");
}
#Bean
public Queue replyQueue() {
return new Queue("response-queue-spring");
}
#Bean
public RabbitAdmin admin() {
return new RabbitAdmin(rabbitConnectionFactory());
}
}

Resources