我已经设置了一个简单的请求/回复类型场景(带有Glassfish的JavaEE 7 / Netbeans 7),代码如下:
这是执行JMS生成者角色的无状态会话bean
destination
和factory
被注入EJB。
public void doStuff(int id) {
try {
Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(destination);
ObjectMessage message = session.createObjectMessage();
MyObject obj = new MyObject(id);
connection.start();
TemporaryQueue replyQueue = session.createTemporaryQueue();
MessageConsumer consumer = session.createConsumer(replyQueue);
message.setJMSReplyTo(replyQueue);
message.setObject(obj);
producer.send(message, DeliveryMode.PERSISTENT, Message.DEFAULT_PRIORITY, 1800000);
Message reply = consumer.receive();
producer.close();
session.close();
connection.close();
} catch (JMSException ex) {
}
}
我的问题是,当调用consumer.receive()
时,执行会按预期阻塞 - 但是此消息的使用者永远不会运行。原始消息的消费者(它是MDB)位于同一Glassfish服务器上部署的另一个netbeans项目中。
我已经尝试调试这两个项目(生产者和消费者),看起来当我的生产者项目阻塞时,我的消费者项目根本没有做任何事情。
如果我将consumer.recieve()
更改为类似consumer.receive(20000)
的内容,那么预期20秒内不会发生任何事情 - 但是一旦超时突然到期我就会在我的消费者项目中获得调试器断点它正常处理。但当然没有回复发送回我的制片人项目,因为它不再听了!
我的其他项目(消费者项目)看起来像这样:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/myQueue")
})
---------------------
@Override
public void onMessage(Message message) {
try {
ObjectMessage objMessage = (ObjectMessage) message;
MyObject obj = (MyObject) objMessage.getObject();
Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(message.getJMSReplyTo());
connection.start();
try {
myMethod(obj);
} catch (Exception e) {
Message response = session.createTextMessage(e.getMessage());
producer.send(message.getJMSReplyTo(), response);
}
} catch (JMSException ex) {
}
}
如何让receive()方法正常工作?我需要它暂停一个回复,但暂停时我需要我的其他项目继续工作 - 我认为如果他们是两个单独部署的项目,他们仍然在不同的线程上。
答案 0 :(得分:0)
我最终发现我遇到了这个问题,因为我的doStuff()
方法正在运行容器管理事务。
除此之外,每个交易只能执行一个操作(例如:只有一个请求/接收)
因此,当我调用producer.send()
时,实际上并未发送消息,因为事务尚未完成(方法尚未完成)。然后它继续进行receive
通话并在那里被阻止,因为没有发送任何消息。
我通过使我的doStuff()方法成为Bean管理事务来解决这个问题,我在bean上注入了一个带有UserTransaction
注释的@Resource
对象。
我通过UserTransaction.begin
和UserTransaction.commit
绑定了发送操作,我重复此操作以绑定我的第二个接收操作 - 它按预期工作。
这为我提供了有关CMT的明确解释:http://docs.oracle.com/cd/E19798-01/821-1841/bncij/index.html