有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java JMS TransactionRolledbackLocalException导致GlassFish崩溃

我的基本问题:
MessageDrivenbean在某处抛出一个Exception,这会导致JMS Queue中的回滚,直到它爆炸并且服务器崩溃。我甚至找不到Exceptions来解决这个问题,因为服务器日志在几分钟内就增长到几百MB

我在找什么:
一种先清除JMS Queue,然后一次性停止回滚的方法

我就是这么做的:


   the object         stateless bean to         Message-Driven Bean     here it throws
 I want to send     send the ObjectMessage     to receive the message   the Exception
  +-----------+      +-----------------+        +-----------------+     +----------+
  |  MyObject |----->| MessageProducer |------->| MessageReceiver |---->| do stuff |
  +-----------+      +-----------------+        +-----------------+     +----------+  

我发送的对象是一个简单的serializablePOJO

消息生产者如下所示:

@Stateless
public class MessageProducer{

    @Resource(mappedName = "jms/JMSConnectionFactory")
    private ConnectionFactory connectionFactory;

    @Resource(mappedName = "jms/MessageReceiver")
    Queue messageReceiver;

    public void sendMessage(PostContainer postContainer){          
        MessageProducer messageProducer;
        // try with resources to close everything on Exception
        try(Connection connection = connectionFactory.createConnection(); 
               Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)){
            messageProducer = session.createProducer(messageReceiver);

            ObjectMessage objectMessage = session.createObjectMessage();
            objectMessage.setObject(myObject);
            objectMessage.setJMSRedelivered(false);  // this doesn't seem to have any effect  
            messageProducer.send(objectMessage);
            messageProducer.close();
        }catch(Exception ex){
            System.out.err("error when sendingMessage .. ignoring"); // when "ignoring" the Exception I thought to at least save me the enormous log messages
        }
    }
}

消息bean如下所示:

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/MessageReceiver")
})
public class MessageReceiver implements MessageListener{

    public MessageReceiver(){
    }

    @Override
    public void onMessage(Message message){
        try{
            if(message instanceof ObjectMessage){
                ObjectMessage objectMessage = (ObjectMessage) message;
                MyObject myObject = (MyObject) objectMessage.getObject();
                doStuff(myObject); // the method that handles the incoming object - here the Exception gets thrown
            }
        }catch(Exception ex){
           System.err.println("message could not be received: " + ex.getMessage());  // still trying to ignore exceptions here
        }
    }
}

部分例外情况

javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean
    at com.sun.ejb.containers.EJBContainerTransactionManager.checkExceptionClientTx(EJBContainerTransactionManager.java:662)
    at com.sun.ejb.containers.EJBContainerTransactionManager.postInvokeTx(EJBContainerTransactionManager.java:507)
    at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4566)
    ......... (and so on....)
    at com.me.MessageBeans.MessageReceiver.doStuff(MessageReceiver.java:86)
    at com.me.MessageBeans.MessageReceiver.onMessage(MessageReceiver.java:61)
    at sun.reflect.GeneratedMethodAccessor313.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081)
    at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153)
    at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4786)
    at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:656)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
    at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:55)
    at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:52)
    at sun.reflect.GeneratedMethodAccessor310.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
    ......... (and so on....)
Caused by: javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details.

 // I try to persist myObject with JPA into the database (that's what's not working right now.. but it's beside the point here
    ......... (and so on....)

现在我的实际问题是:)
我如何停止我的JMS Queue至^{重新传递消息(导致任何Exceptions或由于任何其他原因无法成功传递)?(例如捕捉异常,在发送消息时设置一些参数…)

在设置目标资源连接工厂时,是否需要在GlassFish中设置参数/选项

我怎样才能手动清除队列呢?因为现在队列已经满了,有“重新传递消息”,每次部署应用程序,我都会在几分钟内收到大量日志消息

感谢大家抽出时间阅读:)


共 (1) 个答案

  1. # 1 楼答案

    MDB中的事务管理很棘手

    发生的情况是,正在从您的JPA Facade服务方法中抛出一个java.lang.RuntimeException,这会自动标记当前事务以进行回滚。因此,当它到达MDB中的catch子句时,已经太晚了。JMS将重试失败的事务

    从服务方法转义的任何java.lang.RuntimeException都将标记MDB的事务以进行回滚。您可以通过在服务方法中捕获它来防止这种情况

    您可能需要在JPA Facade中用@TransactionaAttribute(REQUIRES_NEW)注释服务方法,以防JPA标记Tx(不确定这一点)或服务方法中的另一个EJB调用失败

    您可以按照To Purge Messages From a Physical Destination上的说明清除队列