0

我有一个 MessageBean,它从我们将命名为MainQ 的队列中读取。 如果 onMessage 代码的执行抛出了一个基于用户的异常,我们将其命名为UserException我想捕获它并将此消息放在一个名为UserErrorQ的单独队列中。如果异常不属于此类型,则会引发异常以由 DMQ 处理。

这是我的问题:

  • 在我的 catch 块中,我尝试通过 ErrorQueueHandler 将此新消息放在 UserErrorQ 上。当我尝试连接到 connectionFactory 以将消息发送到 UserErrorQ 时,这会导致错误。
  • 显然创建到 QueueConnectionFactory(javax.jms.ConnectionFactory) 的新连接会导致问题

错误:

com.sun.messaging.jms.JMSException: MQRA:DCF:allocation failure:createConnection:Error in allocating a connection. Cause: javax.transaction.RollbackException 
at com.sun.messaging.jms.ra.DirectConnectionFactory._allocateConnection(DirectConnectionFactory.java:548)
at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:265)
at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:244)`

消息豆:

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void onMessage(Message message) {
   try{
    .
    .
   }catch(Exception e){
       if(isUserExceptionWrappedInException(e){
           errorQueueHandler.sendToErrorQueue(message);
       }
   }
}

private boolean isUserExceptionWrappedInException(Throwable t) {
    if (t == null)
        return false;
    else if (t instanceof UserException)
        return true;
    else
        return isUserExceptionWrappedInException(t.getCause());
}

错误队列处理程序:

public void sendToErrorQueue(Message message) {
    try {
        createConnection();
        send((TextMessage)message);
    } finally {
        closeConnection();
    }
}

private void createConnection() throws Exception {
    try {
        connection = connectionfactory.createConnection();
        connection.start();
    } catch (JMSException e) {
        String msg = "Error while attempting to initialize connection to jms destination " + ERROR_QUEUE;
        throw new OperationalException(msg, e, OperationalExceptionType.APPLIKASJONSTJENER);
    }
}

如前所述,尝试建立连接时会发生错误。有人对此有解决办法吗?

4

1 回答 1

0

所以,我已经找到了我自己问题的答案。connectionException 的原因是 ErrorQueueHandler 不是 EJB,而是通过 CDI 注入的。回滚状态中不允许新的实例化,因为容器丢弃了 bean 实例,这就是它失败的原因。我的 REQUIRES_NEW 注释也被忽略了,因为它属于 javax api,它不会影响 CDI 注入的 bean。

这里有几点需要注意:

  1. 确保 EJB没有构造函数或公共构造函数。修饰符很重要,因为容器需要这些修饰符正确才能实例化 EJB。

  2. 这种方法存在一些问题。

    • 当我尝试将消息写入单独的错误队列而不是 DMQ 时,我将不得不使用该消息并且之后不会引发错误。因为 MDB 处于回滚状态,所以 JMS 规范明确指出这将导致消息被重新传递。您将体验到的是,在写入您自定义的 errorQueue 后,消息将立即反弹回队列,您现在有一个无限循环。

幸运的是我也有一个解决方案:这里的主要问题是控制你的交易。对于这种情况,我需要 3 个事务:

  1. MDB 的一项事务,以便它能够确认消息事件,尽管我有一个 RuntimeException。
  2. onMessage 方法逻辑的一个事务,这样我就可以在遇到异常时进行回滚,但仍然可以写入 ErrorQueue。
  3. 一个用于在回滚状态下连接和写入 ErrorQueue 的事务。

代码:

消息豆:

@EJB
QueueService queueService;

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void onMessage(Message message) {
  try{
    queueService.processMessageInNewTrasaction(message);
  }catch(Exception e){
    throw e;
  }
}

队列服务:

import javax.jms.Message;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Stateless
public class QueueService {

  @EJB
  ErrorQueueHandler errorQueueHandler;

  public void processMessageInNewTransaction(Message message){
    try {
    .
    .
    } catch(Exception e) {
      if(isUserExceptionWrappedInException(e)
        errorQueueHandler.sendToErrorQueue(message);
    }
  }

  private boolean isUserExceptionWrappedInException(Throwable t) {
    if (t == null)
      return false;
    else if (t instanceof UserException)
      return true;
    else
      return isUserExceptionWrappedInException(t.getCause());
  }

}

错误队列处理程序:

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Stateless
public class ErrorQueueHandler{
   public void sendToErrorQueue(Message message){
   .
   .
   }
}

有用的资源:http ://weblogic-wonders.com/weblogic/2011/01/10/working-with-jms-and-the-standard-issues-in-jms/

于 2014-06-12T10:42:55.653 回答