【问题标题】:Spring Container hangs if ActiveMQ is not started如果 ActiveMQ 没有启动,Spring Container 会挂起
【发布时间】:2014-09-06 03:50:55
【问题描述】:

我目前正在使用 DefaultMessageListenerContainer 创建侦听器,并使用 JmsTemplate 将消息(生产者)发送到队列。

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,我的 spring 容器加载过程就会卡住。

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

春天之外,我知道提供的activemq是否没有运行,

activeMQConnection.createSession()

是执行会卡住的地方。在常规的 Java 代码中,我可以使一些长时间的处理/可能卡住的过程超时。但是我怎么能在 spring 容器中做这样的事情呢?

我想知道是否有更好的方法来声明这些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: 我没有退出应用程序(它仍然无法正常工作 - 可能与侦听器有关),而是更改了异常侦听器以使我的实现更有意义。如果触发了异常侦听器,我现在正在尝试让代理启动。

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

【问题讨论】:

  • 查看设置错误处理程序是否会改变任何东西(stackoverflow.com/questions/8922532/…)。您还可以将 autostartup 设置为 false 并在应用启动后启动监听器。
  • 添加错误处理程序没有帮助。错误处理程序也适用于收到消息时发生的错误,并且在此之前发生。我可以更改 DefaultMessageListenerContainer 的自动启动,但 JMSTemplate 也存在同样的问题。 JMSTemplate 中没有这样的方法。

标签: java spring activemq


【解决方案1】:

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

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

【讨论】:

  • 谢谢蒂姆。我按照 activemq 文档上的说明配置了故障转移传输。我已经通过更改更新了我的问题。但是现在发生的事情是,我从“o.a.a.t.failover.FailoverTransport”收到一条错误消息,然后是我的异常监听器“c.b.s.o.b.m.FactoryExceptionListener”。现在,如果未启动 activeMQ,我尝试使应用程序崩溃。但这没有用。此外,现在即使未正确加载 spring 容器(未建立与 MQ 的连接),我的应用程序仍在继续执行,并在 ActiveMQ 未启动时抛出一堆异常。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 1970-01-01
    • 2018-10-30
    • 2016-05-25
    • 2016-03-29
    • 1970-01-01
    • 2018-01-04
    相关资源
    最近更新 更多