Я начинаю проект Java EE, который должен быть сильно масштабируемым. До сих пор концепция была такой:
- несколько компонентов, управляемых сообщениями, отвечающих за разные части архитектуры
- каждый MDB имеет внедренный сеансовый компонент, обрабатывающий бизнес-логику
- пара Entity Beans, обеспечивающая доступ к слою сохранения
- communication between the different parts of the architecture via Request/Reply concept via JMS messages:
- MDB receives msg containing activity request
- использует свой сессионный компонент для выполнения необходимой бизнес-логики
- возвращает объект ответа в msg исходному запрашивающему
Идея заключалась в том, что, отделив части архитектуры друг от друга через шину сообщений, масштабируемость не будет ограничена. Просто запустите больше компонентов — пока они подключены к одной и той же шине, мы можем расти и расти.
К сожалению, у нас серьезные проблемы с концепцией запрос-ответ. Transaction Mgmt, кажется, мешает нам. Похоже, сеансовые компоненты не должны потреблять сообщения?!
Чтение http://blogs.oracle.com/fkieviet/entry/request_reply_from_an_ejb и http://forums.sun.com/message.jspa?messageID=10338789 , я чувствую, что люди на самом деле рекомендуют против концепцию запроса/ответа для EJB.
Если это так, то как сделать обмен данными между вашими EJB? (Помните, мне нужна масштабируемость)
Подробная информация о моей текущей настройке:
- MDB 1 «TestController», использует (локальный) SLSB 1 «TestService» для бизнес-логики
- TestController.onMessage() makes TestService send a message to queue XYZ and requests a reply
- TestService uses Bean Managed Transactions
- TestService устанавливает соединение и сеанс с брокером JMS через совместную фабрику соединений при инициализации (@PostConstruct)
- TestService фиксирует транзакцию после отправки, затем начинает другую транзакцию и ждет ответа 10 секунд.
- Сообщение попадает в MDB 2 «LocationController», который использует (локальный) SLSB 2 «LocationService» для бизнес-логики.
- LocationController.onMessage() makes LocationService send a message back to the requested JMSReplyTo queue
- Same BMT concept, same @PostConstruct concept
- все используют одну и ту же фабрику соединений для доступа к брокеру
Проблема: первое сообщение отправляется (SLSB 1) и принимается (MDB 2) нормально. Отправка ответного сообщения (посредством SLSB 2) также работает нормально. Однако SLSB 1 никогда ничего не получает — просто истекает время ожидания.
Я пробовал без messageSelector, без изменений, по-прежнему не получаю сообщения.
Разве нельзя использовать сообщение сеансовым компонентом?
SLSB 1 — TestService.java
@Resource(name = "jms/mvs.MVSControllerFactory")
private javax.jms.ConnectionFactory connectionFactory;
@PostConstruct
public void initialize() {
try {
jmsConnection = connectionFactory.createConnection();
session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
System.out.println("Connection to JMS Provider established");
} catch (Exception e) { }
}
public Serializable sendMessageWithResponse(Destination reqDest, Destination respDest, Serializable request) {
Serializable response = null;
try {
utx.begin();
Random rand = new Random();
String correlationId = rand.nextLong() + "-" + (new Date()).getTime();
// prepare the sending message object
ObjectMessage reqMsg = session.createObjectMessage();
reqMsg.setObject(request);
reqMsg.setJMSReplyTo(respDest);
reqMsg.setJMSCorrelationID(correlationId);
// prepare the publishers and subscribers
MessageProducer producer = session.createProducer(reqDest);
// send the message
producer.send(reqMsg);
System.out.println("Request Message has been sent!");
utx.commit();
// need to start second transaction, otherwise the first msg never gets sent
utx.begin();
MessageConsumer consumer = session.createConsumer(respDest, "JMSCorrelationID = '" + correlationId + "'");
jmsConnection.start();
ObjectMessage respMsg = (ObjectMessage) consumer.receive(10000L);
utx.commit();
if (respMsg != null) {
response = respMsg.getObject();
System.out.println("Response Message has been received!");
} else {
// timeout waiting for response
System.out.println("Timeout waiting for response!");
}
} catch (Exception e) { }
return response;
}
SLSB 2 — LocationService.Java (только метод ответа, остальное такое же, как указано выше)
public boolean reply(Message origMsg, Serializable o) {
boolean rc = false;
try {
// check if we have necessary correlationID and replyTo destination
if (!origMsg.getJMSCorrelationID().equals("") && (origMsg.getJMSReplyTo() != null)) {
// prepare the payload
utx.begin();
ObjectMessage msg = session.createObjectMessage();
msg.setObject(o);
// make it a response
msg.setJMSCorrelationID(origMsg.getJMSCorrelationID());
Destination dest = origMsg.getJMSReplyTo();
// send it
MessageProducer producer = session.createProducer(dest);
producer.send(msg);
producer.close();
System.out.println("Reply Message has been sent");
utx.commit();
rc = true;
}
} catch (Exception e) {}
return rc;
}
солнце-resources.xml
<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerRequest" res-type="javax.jms.Queue" res-adapter="jmsra">
<property name="Name" value="mvs.LocationControllerRequestQueue"/>
</admin-object-resource>
<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerResponse" res-type="javax.jms.Queue" res-adapter="jmsra">
<property name="Name" value="mvs.LocationControllerResponseQueue"/>
</admin-object-resource>
<connector-connection-pool name="jms/mvs.MVSControllerFactoryPool" connection-definition-name="javax.jms.QueueConnectionFactory" resource-adapter-name="jmsra"/>
<connector-resource enabled="true" jndi-name="jms/mvs.MVSControllerFactory" pool-name="jms/mvs.MVSControllerFactoryPool" />