Как внедрить сеансовый компонент в компонент, управляемый сообщениями?

Я новичок в 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();
}

Вот мой 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 TestBean testBean;

    public TestController() {
    }

    public void onMessage(Message message) {
      testBean.doSomething();
    }
}

Пока не ракетостроение, правда?

К сожалению, при развертывании этого в Glassfish v3 и отправке сообщения в соответствующую очередь JMS я получаю ошибки, связанные с тем, что glassfish не может найти EJB 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]]]

Итак, мои вопросы:

  • Это правильный способ внедрения сеансового компонента в другой компонент (в частности, компонент, управляемый сообщениями)?
  • почему поиск имен не работает?

person Hank    schedule 17.03.2010    source источник


Ответы (4)


Не могли бы вы дать такое определение:

@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();
    }
}

Если это сработает, я постараюсь дать объяснение :)

person Pascal Thivent    schedule 18.03.2010
comment
К сожалению, это тоже не работает. Я думаю, что буду придерживаться того, что узнал о IoC. Спасибо, в любом случае! - person Hank; 18.03.2010

Я думаю, что проблема самого первого примера в том, что вы пытаетесь внедрить реализацию EJB, а не его интерфейс. Локальное представление EJB 3.1 без интерфейса возможно только в том случае, если вы не определяете какой-либо интерфейс, даже удаленный. Таким образом, изменение точки впрыска на следующее должно сработать:

 @EJB
 private TestBeanRemote testBean;

Если вы используете свое приложение в некластеризованной среде, например, с одной JVM, вам следует подумать об изменении интерфейса на @Local. Как только вы получаете доступ к EJB через их удаленный интерфейс, вы получаете много накладных расходов. Параметры и возвращаемые значения больше не могут быть доступны по ссылке, но по значению, поскольку они всегда копируются (так сказано в спецификации). Это может привести к проблемам с производительностью при работе с более сложными объектами.

Надеюсь, что это помогло.

person Roland Tiefenbrunner    schedule 28.01.2012

Кажется, что моя проблема была связана с инверсией управления и вызвана моим недостатком знаний и предложениями Netbeans для имен классов / интерфейсов.

Я обнаружил, что для того, чтобы найти нужный компонент и правильный интерфейс, я должен правильно назвать их. Вот что работает:

@Remote
public interface Test {

  public void doSomething();
}

@Stateless
public class TestBean implements Test {

  public void doSomething() {
    // business logic goes here
  }
}

И в MDB я обращаюсь к «Test» не «TestBean»:

@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();
    }
}
person Hank    schedule 18.03.2010
comment
Можете ли вы добавить ссылку на свои выводы о соглашениях об именах? - person Pascal Thivent; 18.03.2010
comment
Хорошо, теперь я начинаю понимать это все больше и больше. Мой пример выше был бы правильным, если бы интерфейс был @Local. Когда я внедряю во что-то сессионный компонент, я ввожу ‹component-name›. Затем контейнер пытается найти реализующий класс (Bean ‹component-name›), а также соответствующий интерфейс (для использования @Local: ‹component-name› или ‹component-name› Local, для @Remote использования: ‹component- имя ›Пульт). Таким образом, проблема заключалась не в JNDI, а в несоблюдении соглашений об именах! - person Hank; 18.03.2010
comment
Ссылка на документ о правилах присвоения имен больше не работала. Это должно быть правильно: oracle.com/technetwork/java/namingconventions-139351.html - person KFleischer; 16.07.2013

Хорошо, я обнаружил, что если я добавлю аннотацию @LocalBean к сессионному компоненту, это сработает. Что за ...?

person Hank    schedule 17.03.2010
comment
Я немного дальше. @LocalBean идентифицирует bean-компонент без интерфейса. Так что это не то, что я хочу, хотя это работает: D - person Hank; 18.03.2010
comment
Вы должны были использовать @EJB private TestBeanRemote testBean; - person Dagvadorj; 13.04.2013