Я начинаю проект Java EE, который должен быть сильно масштабируемым. Пока что концепция была:
- несколько компонентов, управляемых сообщениями, отвечающих за различные части архитектуры
- в каждый MDB вставлен Session Bean, обрабатывающий бизнес-логику
- пара сущностей, предоставляющих доступ к постоянному слою
- связь между различными частями архитектуры через концепцию запроса / ответа через сообщения JMS:
- MDB получает сообщение, содержащее запрос активности
- использует свой сессионный компонент для выполнения необходимой бизнес-логики
- возвращает объект ответа в сообщении исходному запросчику
Идея заключалась в том, что, отделяя части архитектуры друг от друга через шину сообщений, нет предела масштабируемости. Просто запустите больше компонентов - если они подключены к одной шине, мы можем расти и расти.
К сожалению, у нас огромные проблемы с концепцией запрос-ответ. Транзакции 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 () заставляет TestService отправлять сообщение в очередь XYZ и запрашивать ответ
- TestService использует управляемые бином транзакции
- TestService устанавливает соединение и сеанс с JMS-брокером через фабрику совместных соединений при инициализации (@PostConstruct)
- TestService фиксирует транзакцию после отправки, затем начинает другую транзакцию и ожидает ответа в течение 10 секунд
- Сообщение попадает в MDB 2 'LocationController', который использует (локальную) SLSB 2 'LocationService' для бизнес-логики
- LocationController.onMessage () заставляет LocationService отправлять сообщение back в запрошенную очередь JMSReplyTo
- Та же концепция BMT, та же концепция @PostConstruct
- все используют одну и ту же фабрику соединений для доступа к брокеру
Проблема: первое сообщение отправляется (по SLSB 1) и принимается (по MDB 2) нормально. Отправка ответного сообщения (по SLSB 2) также в порядке. Тем не менее, SLSB 1 никогда ничего не получает - это просто время ожидания.
Я пытался без сообщенияВыбрать, без изменений, все еще без получения сообщения.
Разве не нормально использовать сообщение сессионным компонентом?
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" />