如何将会话Bean注入消息驱动Bean?

时间:2010-03-17 18:55:33

标签: glassfish cdi java-ee-6 ejb-3.1 glassfish-3

我是Java EE的新手,所以这可能是愚蠢的......请耐心等待:D

我想将无状态会话bean注入消息驱动的bean中。基本上,MDB获取JMS消息,然后使用会话bean来执行工作。会话bean保存业务逻辑。

这是我的会话Bean:

@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无法找到TestBean EJB的错误:

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 个答案:

答案 0 :(得分:6)

你能尝试定义这样的事情:

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

如果这项工作,我会尝试提供解释:)

答案 1 :(得分:6)

我认为第一个例子的问题是你试图注入EJB的实现而不是它的接口。如果您没有定义任何接口,甚至远程接口,则只能使用EJB 3.1的本地无接口视图。因此,将注入点更改为以下内容应该可以解决:

 @EJB
 private TestBeanRemote testBean;

如果您在非集群环境中使用应用程序,那么单个JVM,您应该考虑将接口更改为@Local。一旦使用远程接口访问EJB,就会产生大量开销。参数和返回值不能再通过引用访问,而是通过值访问,因为它们总是被复制(规范说明如此)。在处理更复杂的对象时,这可能会导致性能问题。

希望帮助。

答案 2 :(得分:4)

似乎我的问题与控制反转有关,并且由于我缺乏知识和Netbeans对类/接口名称的建议而引起。

我发现 - 为了找到合适的bean和正确的界面 - 我应该正确命名它们。这是有效的:

@Remote
public interface Test {

  public void doSomething();
}

@Stateless
public class TestBean implements Test {

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

在MDB中我访问'测试'而不是'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();
    }
}

答案 3 :(得分:3)

好的,我发现如果我将注释@LocalBean添加到会话bean,它就可以了。什么......?