Как внедрить сеансовый компонент в компонент, управляемый сообщениями?
-
20-09-2019 - |
Вопрос
Я новичок в Java EE, так что это может быть глупо..потерпите меня, пожалуйста :D
Я хотел бы внедрить сеансовый компонент без сохранения состояния в компонент, управляемый сообщениями.По сути, MDB получает сообщение JMS, а затем использует сеансовый компонент для выполнения работы.Сессионный компонент содержит бизнес-логику.
Вот мой сессионный компонент:
@Stateless
public class TestBean implements TestBeanRemote {
public void doSomething() {
// business logic goes here
}
}
Соответствующий интерфейс:
@Remote
public interface TestBeanRemote {
public void doSomething();
}
Вот моя МБД:
@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
@EJB
private TestBean testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}
Пока что не ракетостроение, да?
К сожалению, при развертывании этого в Glassfish v3 и отправке сообщения в соответствующую очередь JMS я получаю ошибки о том, что Glassfish не может найти компонент TestBean:
java.lang.IllegalStateException: Exception attempting to inject Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session into class mvs.test.TestController
Caused by: com.sun.enterprise.container.common.spi.util.InjectionException: Exception attempting to inject Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session into class mvs.test.TestController
Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/mvs.test.TestController/testBean' in SerialContext [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session' . Actual (possibly internal) Remote JNDI name used for lookup is 'mvs.test.TestBean#mvs.test.TestBean' [Root exception is javax.naming.NamingException: Lookup failed for 'mvs.test.TestBean#mvs.test.TestBean' in SerialContext [Root exception is javax.naming.NameNotFoundException: mvs.test.TestBean#mvs.test.TestBean not found]]]
Итак, мои вопросы:
- правильный ли это способ внедрения сеансового bean-компонента в другой bean-компонент (особенно bean-компонент, управляемый сообщениями)?
- почему поиск имен не работает?
Решение 4
Хорошо, я обнаружил, что если добавить аннотацию @LocalBean к сессионному компоненту, это сработает.Что за ...?
Другие советы
Не могли бы вы попытаться определить такие вещи:
@Remote
public interface TestBeanRemote {
public void doSomething();
}
@Stateless(name="TestBeanRemote")
public class TestBean implements TestBeanRemote {
public void doSomething() {
// business logic goes here
}
}
И затем в MDB:
@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
@EJB(beanName="TestBeanRemote")
private TestBeanRemote testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}
Если это сработает, я постараюсь дать объяснение :)
Я думаю, проблема самого первого примера в том, что вы пытаетесь внедрить реализацию EJB, а не его интерфейс.Локальное представление EJB 3.1 без интерфейса возможно, если вы не определяете какой-либо интерфейс, даже удаленный.Таким образом, изменение точки впрыска на следующее должно сработать:
@EJB
private TestBeanRemote testBean;
Если вы используете свое приложение в некластеризованной среде, то есть в одной JVM, вам следует подумать об изменении интерфейса на @Local.Как только вы получаете доступ к EJB, используя их удаленный интерфейс, вы получаете много накладных расходов.Доступ к параметрам и возвращаемым значениям больше не возможен по ссылке, а по значению, поскольку они всегда копируются (так говорит спецификация).Это может привести к проблемам с производительностью при работе с более сложными объектами.
Надеялся, что это помогло.
Кажется, моя проблема была связана с инверсией управления и вызвана недостатком моих знаний и предложениями Netbeans по именам классов/интерфейсов.
Я обнаружил, что для того, чтобы найти правильный компонент и правильный интерфейс, я должен правильно назвать их.Вот что работает:
@Remote
public interface Test {
public void doSomething();
}
@Stateless
public class TestBean implements Test {
public void doSomething() {
// business logic goes here
}
}
И в MDB я получаю доступ к «Тесту» нет «ТестБин»:
@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class TestController implements MessageListener {
@EJB
private Test testBean;
public TestController() {
}
public void onMessage(Message message) {
testBean.doSomething();
}
}