【问题标题】:How to inject a Session Bean into a Message Driven Bean?如何将会话 Bean 注入消息驱动 Bean?
【发布时间】:2010-03-17 18:55:33
【问题描述】:

我对 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)的正确方法吗?
  • 为什么命名查找失败?

【问题讨论】:

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


    【解决方案1】:

    你能试着定义这样的东西吗:

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

    如果可行,我会尝试提供解释:)

    【讨论】:

    • 抱歉,这也不起作用。我想我会选择我对 IoC 的发现。还是谢谢!
    【解决方案2】:

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

     @EJB
     private TestBeanRemote testBean;
    

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

    希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      看来我的问题与控制反转有关,并且是由于我缺乏知识以及 Netbeans 对类/接口名称的建议造成的。

      我发现 - 为了找到正确的 bean 和正确的接口 - 我应该正确命名它们。以下是有效的:

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

      【讨论】:

      • 您能否就您对命名约定的发现添加任何参考?
      • 好的,我现在开始越来越了解这一点。如果接口是@Local,我上面的例子是正确的。当我将会话 bean 注入某些东西时,我正在注入 。然后容器尝试查找实现类(Bean)以及适当的接口(@Local 使用:Local,@Remote 使用:远程)。所以问题不在于 JNDI,它不符合命名约定!
      • 命名约定文档的链接不再有效。这应该是正确的:oracle.com/technetwork/java/namingconventions-139351.html
      【解决方案4】:

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

      【讨论】:

      • 我现在走得更远了。 @LocalBean 标识没有接口的 bean。所以这不是我想要的,即使它有效:D
      • 你应该使用过“@EJB private TestBeanRemote testBean;”
      猜你喜欢
      • 1970-01-01
      • 2013-03-17
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多