Spring MDP - 如何在坏消息上关闭它

时间:2012-03-12 17:46:30

标签: java spring message-queue ibm-mq spring-jms

我使用Spring DefaultMessageListenderContainer实现了一个Spring MDP,它监听WebSphere MQ v7.1上的输入队列。如果有错误消息进入(导致RuntimeException),则当前发生的是,事务被回滚,并且消息被放回队列中。然而,MDP进入无限循环。

问题1:根据我的要求,我希望能够在看到错误消息时关闭处理。无需重试。是否可以正常关闭消息侦听器,以防它看到错误消息(而不是粗略的System.exit()或那种方法)?我绝对不喜欢它进入无限循环。

修改

问题2:有没有办法停止或暂停监听器容器以停止进一步处理消息?

3 个答案:

答案 0 :(得分:2)

处理此问题的常用方法是设置错误队列,并在看到错误消息时将其放入错误队列。
有些系统会为您处理此问题,例如IBM MQ Series。您只需要配置错误队列以及您希望将它放在那里的重试次数。
然后,管理员将查看这些队列并对队列中的消息采取适当的操作(即修复并重新提交)

答案 1 :(得分:1)

实际上,System.exit()太残酷了......不行。在代理(WMQ)端处理失败消息的重试,以便在重新启动应用程序时重新传递消息。

您描述的问题称为,应在代理方处理。它似乎在WMQ手册和Handling poison messages中的How WebSphere Application Server handles poison messages中进行了描述。

答案 2 :(得分:0)

我用以下方式解决了这个问题,不确定这是否是最好的方法,但它有效。

  1. MDP实现ApplicationContextAware;我还维护一个监听器状态(带有OPEN,CLOSE,ERROR值的枚举)下面的MDP代码片段:
  2. //context
    private ConfigurableApplicationContext applicationContext;
    
    //listener state
    private ListenerState listenerState = ListenerState.OPEN;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = (ConfigurableApplicationContext) applicationContext;
    }
    //onMessage method
    public void processMessages(....) {
      try {
        process(...);
      } catch (Throwable t) {
        listenerState = ListenerState.ERROR;           
        throw new RuntimeException(...);            
      }    
    }
    
    @Override
    public void stopContext() {        
      applicationContext.stop();  
    }
    
    1. 在加载spring上下文的java main中,我这样做:
    2.     //check for errors for exit
          Listener listener = (Listener)context.getBean("listener");
          listenerContainer listenerContainer =
                  (ListenerContainer)context.getBean("listenerContainer");
      
          try {
              while(true) {
                  Thread.sleep(1000); //sleep for 1 sec
                  if(!listener.getListenerState().equals(ListenerState.OPEN)) {
                      listener.stopContext();
                      listenerContainer.stop();
                      System.exit(1);
                  }>             }            
          } catch (InterruptedException e) {
              throw new RuntimeException(e);
          }