如果未启动ActiveMQ,Spring Container将挂起

时间:2014-07-15 19:45:08

标签: java spring activemq

我目前正在使用DefaultMessageListenerContainer创建侦听器,而JmsTemplate则将消息(producer)发送到队列。

Spring配置代码段:

@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;
}

我目前遇到的问题是,如果在运行应用程序之前未启动ActiveMQ,我的弹簧容器加载过程会卡住。

我相信DefaultMessageListenerContainer和JmsTemplate正在尝试创建与ActiveMQConnectionFactory的连接和会话。

春天以外,我知道提供的activemq是否正在运行,

activeMQConnection.createSession()

是执行陷入困境的地方。在常规Java代码中,我可以超时一些长处理/可能卡住的进程。但是我怎么能在弹簧容器中做那样的事情呢?

我想知道是否有更好的方法来声明这些bean,以便我知道activemq是否卡住而容器是否卡住了?

提前感谢您的帮助。

更新1:

我更新了连接工厂的连接URL,并添加了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);
}
}

现在是一个愚蠢的问题。

我可以看到错误日志被打印,但是在System.exit(1)之后应用程序没有退出。我在这里做错了吗?

此更改有助于阻止呼叫不再被阻止。但我无法退出,这意味着应用程序开始执行并抛出一堆异常,因为activeMQ不可用。

我反而希望它(暂时)使应用程序崩溃。我怎么能这样做?

更新2: 而不是退出应用程序(它仍然无法工作 - 可能与侦听器有关),我改变了Exception Listener,使我的实现更有意义。如果异常监听器被触发,我现在正试图让Broker Up。

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();
    }
}

但我得到以下异常:

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)

然而,当我尝试从另一个项目执行相同的代码时。我成功地启动并运行了BrokerService。 我不确定这个错误是什么意思以及如何解决它?

更新3: 不确定之前有什么问题,但现在相同的代码正在运行。谢谢你的帮助@Tim

2 个答案:

答案 0 :(得分:1)

原因是您指定的默认URL使用Failover传输。默认情况下,传输将尝试连接到代理,直到您关闭应用程序。 createSession调用正在触发客户端尝试将其连接信息请求发送给Broker,但是在客户端连接到Broker之前不会发生这种情况。

评论中陈述的一个解决方案是禁用自动启动功能,以便会话创建调用在启动时不会执行。但是,如果稍后如果在代理仍处于停机状态时触发会话创建,您仍会遇到挂起。您可以使用failover传输页面上显示的选项,使用一定数量的连接尝试配置故障转移传输。

答案 1 :(得分:0)

如果您只想在第一个实例失败时停止连接过程, 您可以设置参数useKeepAlive=false

我尝试了其他参数超时等似乎不起作用。 useKeepAlive 对我有用。