I am currently using DefaultMessageListenerContainer to create listeners and JmsTemplate to send messages (producer) to queues.
Spring Configuration Snippet:
@Bean
public ActiveMQConnectionFactory connectionFactory() {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_BROKER_URL);
factory.setRedeliveryPolicy(desiredRedeliveryPolicy());
return factory;
}
@Bean
public DefaultMessageListenerContainer requestMessageListenerContainer() {
DefaultMessageListenerContainer requestMessageListenerContainer = new DefaultMessageListenerContainer();
requestMessageListenerContainer.setConcurrentConsumers(noOfconcurrentConsumers);
requestMessageListenerContainer.setConnectionFactory(connectionFactory());
requestMessageListenerContainer.setDestinationName(requestQueueName);
requestMessageListenerContainer.setMessageListener(requestMessageListener());
requestMessageListenerContainer.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
requestMessageListenerContainer.setSessionTransacted(false);
return requestMessageListenerContainer;
}
@Bean
public JmsTemplate requestJmsTemplate() {
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(connectionFactory());
jmsTemplate.setDefaultDestination(requestMqQueue());
return jmsTemplate;
}
The issue that I am currently having is that my spring container loading process gets stuck if the ActiveMQ is not started before running the application.
I believe that the DefaultMessageListenerContainer and JmsTemplate are trying to create their connections and session to the ActiveMQConnectionFactory.
Outside of spring, I know if the activemq provided isnt running,
activeMQConnection.createSession()
is where the execution would get stuck. In a regular Java code I can timeout some long processing/potentially stuck process. But how can I do something like that in spring container?
I would like to know if there is any better way to declare these beans so that I would know if the activemq is stuck and the container doesn't get stuck?
Thanks in advance for any help.
Update 1:
I updated my Connection URL for Connection Factory and also added an ExceptionListener:
@Bean
public ActiveMQConnectionFactory connectionFactory() {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(String.format("failover://(%s)?startupMaxReconnectAttempts=1&maxReconnectAttempts=2", ActiveMQConnectionFactory.DEFAULT_BROKER_BIND_URL));
factory.setRedeliveryPolicy(desiredRedeliveryPolicy());
factory.setExceptionListener(factoryExceptionListener());
return factory;
}
public FactoryExceptionListener factoryExceptionListener(){
return new FactoryExceptionListener();
}
public class FactoryExceptionListener implements ExceptionListener {
private static XLogger LOG = XLoggerFactory.getXLogger(FactoryExceptionListener.class);
@Override
public void onException(JMSException exception) {
LOG.error("Factory Exception Caught: "+exception.getMessage());
System.exit(1);
}
}
Now a stupid Question.
I can see the error log getting printed, but the application isn't exiting after System.exit(1). Am I doing something wrong here?
This change helped with the blocking call not being blocking anymore. But I am not able to exit and that means application starts execution and throws a bunch of exceptions as activeMQ isnt available.
What I instead want it to (for now) crash the application. How can I do that?
Update 2: Instead of exiting out of the application (which is still not working - maybe something to do with the listener) I changed the Exception Listener to make a little more sense for my implementation. I am now trying to get the Broker Up if exception listener is triggered.
public void onException(JMSException exception) {
LOG.error("Factory Exception Caught: "+exception.getMessage());
try {
BrokerService brokerService = new BrokerService();
brokerService.addConnector("tcp://localhost:61616");
brokerService.setDataDirectory("C:/temp/data");
brokerService.setEnableStatistics(true);
brokerService.setPersistent(true);
brokerService.start();
} catch (Exception e) {
e.printStackTrace();
}
}
But I am getting following exception:
2014-07-16 10:24:35.009 [ActiveMQ Task-1] ERROR o.a.a.t.failover.FailoverTransport - Failed to connect to [tcp://localhost:61616] after: 1 attempt(s)
2014-07-16 10:24:35.012 [ActiveMQ Connection Executor: unconnected] ERROR c.b.s.o.b.m.FactoryExceptionListener - Factory Exception Caught: Connection refused: connect
Exception in thread "ActiveMQ Connection Executor: unconnected" java.lang.NoSuchMethodError: org.apache.activemq.transport.TransportFactory.bind(Lorg/apache/activemq/broker/BrokerService;Ljava/net/URI;)Lorg/apache/activemq/transport/TransportServer;
at org.apache.activemq.broker.BrokerService.createTransportConnector(BrokerService.java:2249)
at org.apache.activemq.broker.BrokerService.addConnector(BrokerService.java:291)
at org.apache.activemq.broker.BrokerService.addConnector(BrokerService.java:281)
at com.bhn.service.ordermgmt.bulkorder.mq.FactoryExceptionListener.onException(FactoryExceptionListener.java:19)
at org.apache.activemq.ActiveMQConnection$5.run(ActiveMQConnection.java:1998)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
However when I tried to execute the same code from another project. I was successfully able to get the BrokerService up and running. I am not sure what this error means and how to resolve it?
Update 3: Not sure what was wrong earlier but the same code is working now. Thanks for your help @Tim