【问题标题】:EJB3 - Inject a MDB into another MDB?EJB3 - 将一个 MDB 注入另一个 MDB?
【发布时间】:2011-11-23 18:03:23
【问题描述】:

由于消息驱动 bean 是一种 EJB,我希望我能够将一个注入另一个,但我遇到了问题。我必须向 MDB 注入一个类似这样的东西:

@MessageDriven(mappedName = "jms/QueueOne")
public class MessageBeanOne
{
    @EJB
    private EntityService service;

    @EJB
    private MessageBeanTwo mdbTwo;

    public void onMessage(Message message)
    {
        log.info("Received message from jms/QueueOne: " + message);
        String entityId= null;

        try
        {
            if (message instanceof TextMessage)
            {
                entityId = ((TextMessage) message).getText();
            }
            else
            {
                // error handling
            }
        }
        catch (Exception ex)
        {
           // error handling
        }

        Entity myEntity = service.getEntity(entityId);
        mdbTwo.process(myEntity);
    }
}


@MessageDriven(mappedName = "jms/TopicOne")
public class MessageBeanTwo
{
    @EJB
    private EntityService service;

    private boolean goodToProcess = true;

    public void process(Entity entity)
    {
        while(goodToProcess)
        {
            // process entity using injected service object
        }
    }

    public void onMessage(Message message)
    {
        log.info("Received message from jms/TopicOne: " + message);
        String status = null;

        try
        {
            if (message instanceof TextMessage)
            {
                status = ((TextMessage) message).getText();
            }
            else
            {
                // error handling
            }
        }
        catch (Exception ex)
        {
           // error handling
        }

        if (status.equals("cancel")
        {
            goodToProcess = false;
        }
    }
}

它们被部署为 Glassfish 3.1.1 中的耳朵。我在 server.log 中收到此错误消息:

[#|2011-11-23T10:55:35.546-0700|SEVERE|glassfish3.1.1|javax.enterprise.system.container.ejb.mdb.com.sun.ejb.containers|_ThreadID=19;_ThreadName=Thread-2;|MDB00050: Message-driven bean [MyApp-ear-1.0:MessageBeanOne]: Exception in creating message-driven ejb : [com.sun.enterprise.container.common.spi.util.InjectionException: Exception attempting to inject Remote ejb-ref name=my.package.MessageBeanOne/messageBeanTwo,Remote 3.x interface =my.package.MessageBeanTwo,ejb-link=null,lookup=,mappedName=,jndi-name=my.package.MessageBeanTwo,refType=Session into class my.package.MessageBeanOne: Lookup failed for 'java:comp/env/my.package.MessageBeanOne/messageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}]|#]
[#|2011-11-23T10:55:35.547-0700|SEVERE|glassfish3.1.1|javax.enterprise.system.container.ejb.mdb.com.sun.ejb.containers|_ThreadID=19;_ThreadName=Thread-2;|com.sun.enterprise.container.common.spi.util.InjectionException com.sun.enterprise.container.common.spi.util.InjectionException: Exception attempting to inject Remote ejb-ref name=my.package.MessageBeanOne/messageBeanTwo,Remote 3.x interface =my.package.MessageBeanTwo,ejb-link=null,lookup=,mappedName=,jndi-name=my.package.MessageBeanTwo,refType=Session into class my.package.MessageBeanOne: Lookup failed for 'java:comp/env/my.package.MessageBeanOne/messageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}
        at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:703)
        at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.inject(InjectionManagerImpl.java:470)
        at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:171)
        at com.sun.ejb.containers.BaseContainer.injectEjbInstance(BaseContainer.java:1691)
        at com.sun.ejb.containers.MessageBeanContainer.createMessageDrivenEJB(MessageBeanContainer.java:706)
        at com.sun.ejb.containers.MessageBeanContainer.access$100(MessageBeanContainer.java:101)
        at com.sun.ejb.containers.MessageBeanContainer$MessageBeanContextFactory.create(MessageBeanContainer.java:483)
        at com.sun.ejb.containers.util.pool.NonBlockingPool.getObject(NonBlockingPool.java:247)
        at com.sun.ejb.containers.MessageBeanContainer._getContext(MessageBeanContainer.java:547)
        at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:2528)
        at com.sun.ejb.containers.MessageBeanContainer.beforeMessageDelivery(MessageBeanContainer.java:989)
        at com.sun.ejb.containers.MessageBeanListenerImpl.beforeMessageDelivery(MessageBeanListenerImpl.java:77)
        at com.sun.enterprise.connectors.inbound.MessageEndpointInvocationHandler.invoke(MessageEndpointInvocationHandler.java:139)
        at $Proxy337.beforeDelivery(Unknown Source)
        at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java:247)
        at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:114)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)
Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/my.package.MessageBeanOne/messageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=my.package.MessageBeanOne/messageBeanTwo,Remote 3.x interface =my.package.MessageBeanTwo,ejb-link=null,lookup=,mappedName=,jndi-name=my.package.MessageBeanTwo,refType=Session' .  Actual (possibly internal) Remote JNDI name used for lookup is 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' [Root exception is javax.naming.NamingException: Lookup failed for 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: my.package.MessageBeanTwo#my.package.MessageBeanTwo not found]]]
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:599)
        ... 17 more
Caused by: javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=my.package.MessageBeanOne/messageBeanTwo,Remote 3.x interface =my.package.MessageBeanTwo,ejb-link=null,lookup=,mappedName=,jndi-name=my.package.MessageBeanTwo,refType=Session' .  Actual (possibly internal) Remote JNDI name used for lookup is 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' [Root exception is javax.naming.NamingException: Lookup failed for 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: my.package.MessageBeanTwo#my.package.MessageBeanTwo not found]]
        at com.sun.ejb.EjbNamingReferenceManagerImpl.resolveEjbReference(EjbNamingReferenceManagerImpl.java:178)
        at com.sun.enterprise.container.common.impl.ComponentEnvManagerImpl$EjbReferenceProxy.create(ComponentEnvManagerImpl.java:1106)
        at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:776)
        at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:744)
        at com.sun.enterprise.naming.impl.JavaURLContext.lookup(JavaURLContext.java:172)
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:498)
        ... 21 more
Caused by: javax.naming.NamingException: Lookup failed for 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: my.package.MessageBeanTwo#my.package.MessageBeanTwo not found]
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at com.sun.ejb.EjbNamingReferenceManagerImpl.resolveEjbReference(EjbNamingReferenceManagerImpl.java:173)
        ... 26 more
Caused by: javax.naming.NameNotFoundException: my.package.MessageBeanTwo#my.package.MessageBeanTwo not found
        at com.sun.enterprise.naming.impl.TransientContext.doLookup(TransientContext.java:248)
        at com.sun.enterprise.naming.impl.TransientContext.lookup(TransientContext.java:215)
        at com.sun.enterprise.naming.impl.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:77)
        at com.sun.enterprise.naming.impl.LocalSerialContextProviderImpl.lookup(LocalSerialContextProviderImpl.java:119)
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:505)
        ... 30 more
|#]

[#|2011-11-23T10:55:35.548-0700|WARNING|glassfish3.1.1|javax.resourceadapter.mqjmsra.inbound.message|_ThreadID=19;_ThreadName=Thread-2;|MQJMSRA_MR2001: run:Caught Exception from onMessage():Redelivering:
javax.ejb.EJBException: ESwimMessageBeanTwo-ear-1.0:MessageBeanOne: message-driven bean invocation closed by container
        at com.sun.ejb.containers.MessageBeanContainer.deliverMessage(MessageBeanContainer.java:1163)
        at com.sun.ejb.containers.MessageBeanListenerImpl.deliverMessage(MessageBeanListenerImpl.java:81)
        at com.sun.enterprise.connectors.inbound.MessageEndpointInvocationHandler.invoke(MessageEndpointInvocationHandler.java:171)
        at $Proxy337.onMessage(Unknown Source)
        at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java:260)
        at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:114)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)
|#]

在尝试搜索这是否真的可行时,我遇到了很多关于将 MDB 注入会话 bean,但从未将 MDB 注入另一个 MDB 的参考。也许这不可行?

【问题讨论】:

  • 它们是“消息驱动的”bean,你为什么要尝试将一个注入另一个。您是否尝试自己调用onMessage() 方法?
  • MessageBeanTwo 有一个 MessageBeanOne 调用的 process() 方法。他没有调用 onMessage() 而是调用了这个 process() 方法。
  • 最初,MessageBeanOne 创建了一个 MessageBeanTwo 的新实例来进行处理,但由于它没有被注入(因此不是容器管理),所以出现了问题。
  • 我编辑了示例以显示 MessageBeanTwo 还使用了注入的 EntityService 对象。如果 MessageBeanOne 通过“new”获得了 MessageBeanTwo 的实例,则 EntityService 为空。因此需要将 MessageBeanTwo 注入到 MessageBeanOne 中。希望澄清。

标签: java jakarta-ee ejb-3.1


【解决方案1】:

可能与问题没有直接关系,但我会将process() 方法提取到两个MDB 都可以修改的自己的类中。这样,MDB 就有了处理传入消息的sole responsibility,而第三个新类执行“实体处理”。 然后这个类可能是您在两个 MDB 中注入的另一个 EJB。

在我看来,MDB 通常应该只专门用于处理接收消息。

编辑

通过再次查看您的代码,我鼓励您三思而后行。您的 MDB 具有状态,考虑到容器创建实例池,这可能会导致意外结果。您可能处于MessageBeanTwo 的实例与goodToProcess = false 合并的情况。如果从池中取出该实例并注入MessageBeanOne 并调用process() 方法,则可能会得到错误的结果。

这一切都假设您可以将 MDB 注入另一个 MDB,这是我从未做过或听说过的。

【讨论】:

  • 是的,我同意,我会将实际处理工作交给另一个 Session bean。
  • 我喜欢将 MDB2 分离为一个 MDB 和一个(有状态的)会话 bean 的想法。但是,如果 Session bean 被注入到两个 MDB 中,我如何确保它是同一个?
  • 更正,应该是 Statelss Session bean。
  • 我实际上担心在两个 MDB 之间创建依赖关系的整个想法,甚至在主题和它们从中消费的队列之间创建依赖关系。你能给出你想要达到的目标的功能描述吗?
  • 该应用程序是一个批处理器。批次通过部署为单独的 web 应用程序的 servlet 上传。它进行文件验证,保存到数据库并将消息发送到批量接收队列。上面的 MDB1 监听这些消息,从数据库中检索批处理信息,创建一个处理器并开始处理。处理器是 MDB2。最初,它创建了一个“新的”MDB2,但导致了上述问题。 MDB2 是 MDB 的原因是它侦听另一个队列上的消息,指示应该暂停/恢复/取消特定批次的处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-12
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 2010-10-05
  • 2020-02-19
相关资源
最近更新 更多