Do we need to start ActiveMQ when configuring through spring? - activemq

I get connection refused errors when i try to test activemq using spring jms integration. Do i need to start the activemq server or something? From my understanding spring would have all the methods to start the active mq when i setup the brokerconnction
source
#SpringBootApplication
#EnableJms
public class Application {
#Bean
public DefaultJmsListenerContainerFactory myJmsContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
return factory;
}
#Bean
public JmsTemplate jmsTemplate(){
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setDefaultDestination(new ActiveMQQueue("jms.queue"));
jmsTemplate.setConnectionFactory(connectionFactory());
return jmsTemplate;
}
#Bean
public ActiveMQConnectionFactory connectionFactory(){
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("tcp://:61616");
activeMQConnectionFactory.setBrokerURL("tcp://localhost:61616");
return activeMQConnectionFactory;
}
public static void main(String[] args){
// Clean out any ActiveMQ data from previous run
FileSystemUtils.deleteRecursively(new File("activemq-data"));
// Launch the application
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
// Send a message
MessageCreator messageCreator = new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("ping!");
}
};
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
System.out.println("Sending a new message");
jmsTemplate.send("mailbox-destination", messageCreator);
}
}
Error
Exception in thread "main" org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is javax.jms.JMSException: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:169)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:497)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:580)
at org.blanc.whiteboard.jms.Application.main(Application.java:67)
Caused by: javax.jms.JMSException: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused

If you use a vm://localhost URL, an in-memory broker will be started on the vm transport; if you use the tcp://... url you need to start an external broker, or add a broker bean to your application.

Related

Spring AMQP lazy queue #RabbitListener and simplify direct reply configuration

at the moment I have the following problem: The external RabbitMQ remote server expects from me first an async reply login message and then a broadcast queue broadcastQueue.MYUSER_123 is created by this remote server. From this I want to consume via #RabbitListener annotation, which is seen in the code example. But i got an error, you can see below.
While debugging I noticed that a container starts this listener before I have executed the login in my code and so it comes to a rejection when connecting against this broadcast queue. I found the post in How to Lazy Load RabbitMQ queue using #Lazy in spring boot? but the problem on my side is, that the autostart did not work and the container is started for the listener. What i'm doing wrong? Is it possible to create lazy queues.?
Another point is: Is there an easy way to make a direct reply configuration for the RabbitMQ template where I can specify the reply address? According to the spring amqp code it seems that you can only make a directy reply connection if you don't specify a reply address yourself. So i need to create a custom container.
Thank you for your help .
Kind Regards
Sven
#SpringBootTest
#Slf4j
class DemoAmqpApplicationTests {
#RabbitListener(queues="broadcastQueue.MYUSER_123",autoStartup = "false")
public void handleMessage(Object obj) {
log.info("{}",obj);
}
#Test
void contextLoads() throws InterruptedException {
Message<User> login = login();
}
Configuration
#Configuration
#Slf4j
#EnableRabbit
public class RabbitMqConfiguration {
#Bean
public RabbitAdmin amqpAdmin(RabbitTemplate rabbitTemplate) {
return new RabbitAdmin(rabbitTemplate);
}
#Bean
public RabbitTemplate rabbitTemplate(#NonNull CachingConnectionFactory connectionFactory,
#NonNull MessageConverter messageConverter,
#NonNull Queue inquiryResponseQueue,
#NonNull RabbitTemplateConfigurer configurer) {
RabbitTemplate rabbitTemplate = new RabbitTemplate();
configurer.configure(rabbitTemplate, connectionFactory);
String username = connectionFactory.getUsername();
configurePostReceiveProcessor(rabbitTemplate);
rabbitTemplate.setMessageConverter(messageConverter);
configurePrepareSendingProcessor(rabbitTemplate, username, inquiryResponseQueue.getName());
configureReply(rabbitTemplate, inquiryResponseQueue);
return rabbitTemplate;
}
private void configureReply(RabbitTemplate rabbitTemplate,
#NonNull Queue inquiryResponseQueue) {
rabbitTemplate.setReplyAddress(inquiryResponseQueue.getName());
rabbitTemplate.setDefaultReceiveQueue(inquiryResponseQueue.getName());
}
#Bean
public SimpleMessageListenerContainer replyListenerContainer(
#NonNull CachingConnectionFactory connectionFactory,
#NonNull List<Queue> inquiryResponseQueue,
#NonNull RabbitTemplate rabbitTemplate,
#NonNull RabbitAdmin rabbitAdmin) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueues(inquiryResponseQueue.get(0));
container.setMessageListener(rabbitTemplate);
return container;
}
#Bean
public Queue privateInquiryResponseQueue(
#NonNull CachingConnectionFactory connectionFactory) {
return new Queue(privateInquiryResponseQueueName(connectionFactory.getUsername()),
false,
true,
true);
}
}
Error Log:
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:721) ~[spring-rabbit-2.3.10.jar:2.3.10]
... 5 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'broadcastQueue.MYUSER_123' in vhost 'app', class-id=50, method-id=10)
autoStartup works fine - something else must be starting the container - add a breakpoint to see what is starting it - are you calling start() on the application context? That will start the container.
Direct reply-to is a special RabbitMQ mode that uses a pseudo queue for replies; for a named reply queue, you need a listener container.
https://docs.spring.io/spring-amqp/docs/current/reference/html/#direct-reply-to

Reply received after timeout when using multiple RabbitTemplate objects

I have a Java Spring Boot 1.5.10 application that I am connecting to two different RabbitMQ servers with. One RabbitMQ server is running on the same host as the Spring Boot application and the other is on a different/remote host.
This version of Spring Boot includes org.springframework.amqp:spring-amqp:jar:1.7.6.RELEASE, by the way. So, here is some of my configuration code that pertains to the local RabbitMQ server:
#Bean
public ConnectionFactory rabbitConnectionFactory() {
CachingConnectionFactory factory = new CachingConnectionFactory(host);
factory.setVirtualHost(vhost);
factory.setUsername(username);
factory.setPassword(password);
factory.setChannelCacheSize(2);
// Add a custom client connection property, which will show up in the Admin UI (useful for troubleshooting).
factory.getRabbitConnectionFactory().getClientProperties().put("Connection Type", "Local");
return factory;
}
#Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory rabbitConnectionFactory,
MessageConverter jackson2JsonMessageConverter) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory);
rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter);
return rabbitTemplate;
}
#Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory rabbitConnectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(rabbitConnectionFactory);
return factory;
}
#Bean
public RabbitAdmin admin(ConnectionFactory rabbitConnectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitConnectionFactory);
rabbitAdmin.afterPropertiesSet();
rabbitAdmin.setAutoStartup(false);
return rabbitAdmin;
}
And here is some of my configuration code for a RabbitMQ server running remotely on another host:
#Bean
public ConnectionFactory remoteConnectionFactory() {
CachingConnectionFactory factory = new CachingConnectionFactory(remoteHost);
factory.setVirtualHost(remoteVhost);
factory.setUsername(remoteUsername);
factory.setPassword(remotePassword);
// By default, only one Channel will be cached, with further requested Channels being created and disposed on demand.
// Consider raising the "channelCacheSize" value in case of a high-concurrency environment.
factory.setChannelCacheSize(3);
factory.setConnectionThreadFactory(new CustomizableThreadFactory("RemoteRabbit-"));
// Add a custom client connection property, which will show up in the Admin UI (useful for troubleshooting).
factory.getRabbitConnectionFactory().getClientProperties().put("Connection Type", "Remote");
return factory;
}
#Bean
public RabbitAdmin remoteAdmin(ConnectionFactory remoteConnectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(remoteConnectionFactory);
rabbitAdmin.setIgnoreDeclarationExceptions(true);
return rabbitAdmin;
}
#Bean
public SimpleRabbitListenerContainerFactory remoteContainerFactory(ConnectionFactory remoteConnectionFactory,
MessageConverter jackson2JsonMessageConverter) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(remoteConnectionFactory);
factory.setConcurrentConsumers(1);
factory.setMessageConverter(jackson2JsonMessageConverter);
factory.setMaxConcurrentConsumers(5);
factory.setDefaultRequeueRejected(false); // on error, don't put back in the queue
return factory;
}
Now comes the good part. I have another RabbitTemplate that I am calling convertSendAndReceive() on which is configured with the remoteConnectionFactory.
#Bean
public RabbitTemplate payTemplate(ConnectionFactory remoteConnectionFactory,
TopicExchange fromExchange, MessageConverter jackson2JsonMessageConverter) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(remoteConnectionFactory);
rabbitTemplate.setReplyAddress(fromExchange.getName() + "/" + buildMyBindingKey());
rabbitTemplate.setReplyTimeout(30000L);
rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter);
return rabbitTemplate;
}
#Bean
public SimpleMessageListenerContainer payReplyContainer(ConnectionFactory remoteConnectionFactory,
RabbitTemplate payTemplate, Queue fromQueue) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(remoteConnectionFactory);
container.setQueues(fromQueue);
container.setMessageListener(payTemplate);
return container;
}
#Bean
public TopicExchange fromExchange(RabbitAdmin remoteAdmin) {
TopicExchange exchange = new TopicExchange("some.from.exchange", true, false);
exchange.setAdminsThatShouldDeclare(remoteAdmin);
return exchange;
}
#Bean
public Queue fromQueue(RabbitAdmin remoteAdmin) {
Queue queue = new Queue("myReplyQueue");
queue.setAdminsThatShouldDeclare(corporateAdmin);
return queue;
}
private String buildMyBindingKey() {
return "someBindingKeyHere";
}
My problem occurs when I call convertSendAndReceive() on the payTemplate. The reply is received fine, but it almost seems to be received twice. This worked when I was connecting to only one RabbitMQ server, but after configuring connections to two servers, I get this:
2018-06-11 18:29:57,156|WARN||payReplyContainer-1|org.springframework.amqp.rabbit.core.RabbitTemplate|||||Reply received after timeout for 1
2018-06-11 18:29:57,165|WARN||payReplyContainer-1|org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler|||||Execution of Rabbit message listener failed.
org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:949)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:902)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:790)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:105)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:208)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1349)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:760)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1292)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1262)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1800(SimpleMessageListenerContainer.java:105)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1518)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.amqp.AmqpRejectAndDontRequeueException: Reply received after timeout
at org.springframework.amqp.rabbit.core.RabbitTemplate.onMessage(RabbitTemplate.java:1759)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:899)
... 10 common frames omitted
Again, the payTemplate does get the reply/response it was waiting for, but its like the container received another message that no one was waiting for. I'm stumped. Any help is appreciated.
Indeed it was an exchange (an extra binding that shouldn't have been there) that was responsible for duplicating the response. Much thanks to Gary for reviewing my code and presumably seeing nothing wrong and suggesting some things to look at.

Spring amqp converter issue using rabbit listener

I think I am missing something here..I am trying to create simple rabbit listner which can accept custom object as message type. Now as per doc it says
In versions prior to 1.6, the type information to convert the JSON had to be provided in message headers, or a custom ClassMapper was required. Starting with version 1.6, if there are no type information headers, the type can be inferred from the target method arguments.
I am putting message manually in to queue using rabbit mq adm in dashboard,getting error like
Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [[B] to [com.example.Customer] for GenericMessage [payload=byte[21], headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=customer, amqp_deliveryTag=1, amqp_consumerQueue=customer, amqp_redelivered=false, id=81e8a562-71aa-b430-df03-f60e6a37c5dc, amqp_consumerTag=amq.ctag-LQARUDrR6sUcn7FqAKKVDA, timestamp=1485635555742}]
My configuration:
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost");
connectionFactory.setUsername("test");
connectionFactory.setPassword("test1234");
connectionFactory.setVirtualHost("/");
return connectionFactory;
}
#Bean
RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
return rabbitTemplate;
}
#Bean
public AmqpAdmin amqpAdmin() {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory());
return rabbitAdmin;
}
#Bean
public Jackson2JsonMessageConverter jackson2JsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
Also question is with this exception message is not put back in the queue.
I am using spring boot 1.4 which brings amqp 1.6.1.
Edit1 : I added jackson converter as above (prob not required with spring boot) and given contenty type on rmq admin but still got below, as you can see above I am not configuring any listener container yet.
Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [[B] to [com.example.Customer] for GenericMessage [payload=byte[21], headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=customer, content_type=application/json, amqp_deliveryTag=3, amqp_consumerQueue=customer, amqp_redelivered=false, id=7f84d49d-037a-9ea3-e936-ed5552d9f535, amqp_consumerTag=amq.ctag-YSemzbIW6Q8JGYUS70WWtA, timestamp=1485643437271}]
If you are using boot, you can simply add a Jackson2JsonMessageConverter #Bean to the configuration and it will be automatically wired into the listener (as long as it's the only converter). You need to set the content_type property to application/json if you are using the administration console to send the message.
Conversion errors are considered fatal by default because there is generally no reason to retry; otherwise they'd loop for ever.
EDIT
Here's a working boot app...
#SpringBootApplication
public class So41914665Application {
public static void main(String[] args) {
SpringApplication.run(So41914665Application.class, args);
}
#Bean
public Queue queue() {
return new Queue("foo", false, false, true);
}
#Bean
public Jackson2JsonMessageConverter converter() {
return new Jackson2JsonMessageConverter();
}
#RabbitListener(queues = "foo")
public void listen(Foo foo) {
System.out.println(foo);
}
public static class Foo {
public String bar;
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
#Override
public String toString() {
return "Foo [bar=" + this.bar + "]";
}
}
}
I sent this message
With this result:
2017-01-28 21:49:45.509 INFO 11453 --- [ main] com.example.So41914665Application : Started So41914665Application in 4.404 seconds (JVM running for 5.298)
Foo [bar=baz]
Boot will define an admin and template for you.
Ran into the same issue, turns out that, git stash/merge messed up with my config, I need to include this package again in my main again:
#SpringBootApplication(scanBasePackages = {
"com.example.amqp" // <- git merge messed this up
})
public class TeamActivityApplication {
public static void main(String[] args) {
SpringApplication.run(TeamActivityApplication.class, args);
}
}

JMS Topic sender is throwing exception Null pointer exception for the connection Factory

I am trying to make a simple JMS topic sender.In the code its returning error in the very first line ,where I am creating a connection using ConnectionFactory.
public class TopicSender {
#Resource(lookup = "ConnectionFactoryTest1")
private static ConnectionFactory connectionFactory;
#Resource(lookup ="myTopic")
private static Topic topic;
public static void main(String[] args) throws JMSException{
//Create a connection
Connection connection =connectionFactory.createConnection();
//Get a session
Session session =connection.createSession();
MessageProducer producer=session.createProducer(topic);
//Send a test message to the topic
TextMessage message = session.createTextMessage();
message.setText("This test message sent at" + new Date());
producer.send(message);
session.close();
connection.close();
}
Console output:
Exception in thread "main" java.lang.NullPointerException
at com.aman.JMS.Test1.TopicSender.main(TopicSender.java:23)
Can anybody help me understand why I am getting this exception.
I am using GlassFish server.

RabbitMQ request/response "RabbitTemplate is not configured as listener"

I'm testing request/response pattern with Spring-AMQP rabbitmq implementation and I can't make it work...
I've got configured following artifacts:
test_exchange with greeting queue. Routing key = greeting
reply_exchange with replies queue. Routing key = replies
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory =
new CachingConnectionFactory("....IP of broker...");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
return connectionFactory;
}
#Bean
public Queue greeting() {
return new Queue("greeting");
}
#Bean
public Queue replies() {
return new Queue("replies");
}
MessageListener receiver() {
return new MessageListenerAdapter(new RabbitMqReceiver(), "onMessage");
}
#Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, Queue replies) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setExchange("test_exchange");
template.setRoutingKey("greeting");
template.setReplyAddress("reply_exchange"+"/"+replies.getName());
template.setReplyTimeout(60000);
return template;
}
#Bean
public SimpleMessageListenerContainer replyContainer(ConnectionFactory connectionFactory,
RabbitTemplate rabbitTemplate, Queue replies) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setMessageListener(rabbitTemplate);
container.setQueues(replies);
return container;
}
#Bean
public SimpleMessageListenerContainer serviceListenerContainer(
ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueues(greeting());
container.setMessageListener(receiver());
return container;
}
I was following example at github, but it crashes with:
Caused by: java.lang.IllegalStateException: RabbitTemplate is not configured as
MessageListener - cannot use a 'replyAddress': reply_exchange/replies
Documentation says:
Starting with version 1.5, the RabbitTemplate will detect if it has been configured as a MessageListener to receive replies. If not, attempts to send and receive messages with a reply address will fail with an IllegalStateException (because the replies will never be received).
This is excellent, but how RabbitTemplate does that? How does it detect if it's configured as MessageListener?
thanks in advance
PS: Send code:
public void send() {
Message message = MessageBuilder.withBody("Payload".getBytes())
.setContentType("text/plain")
.build();
Message reply = this.template.sendAndReceive(message);
System.out.println("Reply from server is: "+new String(reply.getBody()));
}
When the reply container starts, it detects that the template is ListenerContainerAware and calls expectedQueueNames() to retrieve the reply queues (or null if the replyAddress has the form exch/rk); if a non-null result is returned, the container checks that the queue is correct; if exch/rk is the reply address, you would get this
logger.debug("Cannot verify reply queue because it has the form 'exchange/routingKey'");
This method unconditionally sets the isListener boolean which avoids that exeption. So it seems like the container hasn't started before you sent your message - are you sending before the context is fully initialized?
Note that since RabbitMQ implemented direct reply-to, it is generally not necessary any more to use a reply container (unless you want HA reply queues or need an explicit reply queue for some other reason). Direct reply-to removed the performance problem that drove us to implement the reply container mechanism.
Gary, your intuition was perfect, as always.
I changed my send code from:
#SpringBootApplication
public class App
{
#Bean(initMethod="send")
public RabbitMqSender sender() {
final RabbitMqSender sender = new RabbitMqSender();
return sender;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}
to:
#SpringBootApplication
public class App
{
public static void main(String[] args) throws Exception {
final ConfigurableApplicationContext configAppContext = SpringApplication.run(App.class, args);
final RabbitMqSender sender = configAppContext.getBean(RabbitMqSender.class);
sender.send();
}
}
to ensure to be sending when all beans are ready and request/response WORKS EXCELLENT!
Yes, I will definitelly try Direct-TO pattern as well.
Thanks you Gary for help.
regards
Tomas