Java 部署后立即使用MDB中EJB的运行时查找

Java 部署后立即使用MDB中EJB的运行时查找,java,jakarta-ee,jboss,jboss5.x,Java,Jakarta Ee,Jboss,Jboss5.x,我有一个使用JBoss5.1的JavaEE5项目和类似的问题。我必须使用消息内容产生的字符串在MDB中对某些EJB执行某种运行时查找。这只是MDB中使用的一种服务定位器模式。现在,由于MDB在部署之后才开始使用,我有很多NameNotFoundException,因为隐式部署顺序在这里不起作用(运行时查找)。你觉得怎么样?使用EJB3.0真的可以做得很好吗?如果解决了问题,我也可以使用任何特定于供应商的东西(JBoss5.1) 一些代码片段可以直观地显示情况: @MessageDriven(ma

我有一个使用JBoss5.1的JavaEE5项目和类似的问题。我必须使用消息内容产生的字符串在MDB中对某些EJB执行某种运行时查找。这只是MDB中使用的一种服务定位器模式。现在,由于MDB在部署之后才开始使用,我有很多
NameNotFoundException
,因为隐式部署顺序在这里不起作用(运行时查找)。你觉得怎么样?使用EJB3.0真的可以做得很好吗?如果解决了问题,我也可以使用任何特定于供应商的东西(JBoss5.1)

一些代码片段可以直观地显示情况:

@MessageDriven(mappedName="jms/Queue")
public class MessageBean implements MessageListener {

    @Resource
    private MessageDrivenContext mdc;

    public void onMessage(Message msg) {

        final String beanName = // extract somehow the bean's name from 'msg'
        final Context ctx = new InitialContext();
        final Object obj = ctx.lookup(beanName); // NameNotFoundException
        // do something with 'obj'
    }
}

一种方法是创建一个虚拟ejb,将其注入到MDB中,这样您的MDB就不会开始使用,直到注入真正发生

如果虚拟ejb与您打算在其上执行动态查找的ejb捆绑在一起,那么这应该可以工作


我的答案解决了一个类似的用例。

使用这四种不同的方法之一

  • 使用“@EJB”注释声明EJB依赖项(EJB引用)(不要使用JNDI查找)。对于实体bean引用,必须引用实体bean主接口。容器必须确保在处理方法/消息侦听器之前注入所有依赖项:

    消息驱动(mappedName=“jms/Queue”)
    公共类MessageBean实现MessageListener{

    @EJB private EntityBeanHomeA entityBeanHomeA;    
    
    @EJB private EntityBeanHomeB entityBeanHomeB;    
    
    @EJB private EntityBeanHomeC entityBeanHomeC;    
    
    @EJB private SessionBeanD sessionBeanD;    
    
    @Resource
    private MessageDrivenContext mdc;
    
    public void onMessage(Message msg) {
    
        final String beanName = // extract somehow the bean's name from 'msg'
        final Object obj = getDependentEJB(beanName);
        // do something with 'obj'
    }
    
    private Object getDependentEJB(String beanName) {
        Object result = null;
        if ("EntityBeanHomeA".equals(beanName)) {
             result = entityBeanHomeA;
        else if ("EntityBeanHomeB".equals(beanName)) {
             result = entityBeanHomeB;
        else ("EntityBeanHomeC".equals(beanName)) {
             result = entityBeanHomeC;
        else ("SessionBeanD".equals(beanName)) {
             result = sessionBeanD;
        }
        return result;
    }
    
    // as given in the original Question...
    
    }

  • 使用JNDI查找,但通过EJB部署描述符声明EJB依赖项。同样,容器必须确保在处理方法/消息之前设置了所有依赖项:

    @消息驱动(mappedName=“jms/Queue”) 公共类MessageBean实现MessageListener{

    @EJB private EntityBeanHomeA entityBeanHomeA;    
    
    @EJB private EntityBeanHomeB entityBeanHomeB;    
    
    @EJB private EntityBeanHomeC entityBeanHomeC;    
    
    @EJB private SessionBeanD sessionBeanD;    
    
    @Resource
    private MessageDrivenContext mdc;
    
    public void onMessage(Message msg) {
    
        final String beanName = // extract somehow the bean's name from 'msg'
        final Object obj = getDependentEJB(beanName);
        // do something with 'obj'
    }
    
    private Object getDependentEJB(String beanName) {
        Object result = null;
        if ("EntityBeanHomeA".equals(beanName)) {
             result = entityBeanHomeA;
        else if ("EntityBeanHomeB".equals(beanName)) {
             result = entityBeanHomeB;
        else ("EntityBeanHomeC".equals(beanName)) {
             result = entityBeanHomeC;
        else ("SessionBeanD".equals(beanName)) {
             result = sessionBeanD;
        }
        return result;
    }
    
    // as given in the original Question...
    
    }

    部署描述符:

    <enterprise-beans>
        <message-driven>
            ... 
            <ejb-name>MessageBean</ejb-name>
            <ejb-class>com.company.pkg.MessageBean</ejb-class> 
            <messaging-type>javax.jms.MessageListener</messaging-type>
            <message-destination-type>javax.jms.Queue</message-destination-type>
            <message-destination-link>ExpenseProcessingQueue</message-destination-link>
            <ejb-ref> 
                <description> This is a reference to an EJB 2.1 entity bean
                  that encapsulates access to employee records. 
                </description>
                <ejb-ref-name>ejb/EmplRecord</ejb-ref-name>
                <ejb-ref-type>Entity</ejb-ref-type>
                <home>com.wombat.empl.EmployeeRecordHome</home>
                <remote>com.wombat.empl.EmployeeRecord</remote> 
                <ejb-link>EmployeeRecord</ejb-link> <-- if in same EJB jar -->
                          <-- ../emp/emp.jar#EmployeeRecord   if in diff EJB jar -->
            </ejb-ref>
            <ejb-local-ref> 
                <description> This is a reference to the local business interface
                   of an EJB 3.0 session bean that provides a payroll service. 
                </description> 
                <ejb-ref-name>ejb/Payroll</ejb-ref-name>
                <local>com.aardvark.payroll.Payroll</local> 
                <ejb-link>Payroll</ejb-link> 
            </ejb-local-ref>
            <ejb-local-ref> 
                <description> This is a reference to the local business interface of an
                  EJB 3.0 session bean that provides a pension plan service. 
                </description>
                <ejb-ref-name>ejb/PensionPlan</ejb-ref-name>
                <local>com.wombat.empl.PensionPlan</local> 
                <ejb-link>PensionPlan</ejb-link> <-- if in same EJB jar -->
            </ejb-local-ref> 
            ...
        </message-driven>
        ... 
    </enterprise-beans>
    
    
    ... 
    MessageBean
    com.company.pkg.MessageBean
    javax.jms.MessageListener
    javax.jms.Queue
    费用处理队列
    这是对EJB2.1实体bean的引用
    它封装了对员工记录的访问。
    ejb/emplocrd
    实体
    com.wombat.EmployeeRecordHome
    com.wombat.EmployeeRecord
    雇员记录
    这是对本地业务接口的引用
    提供工资单服务的EJB3.0会话bean。
    ejb/工资单
    com.aardvark.payroll.payroll
    工资名单
    这是对本地业务接口的引用
    EJB3.0会话bean,提供养老金计划服务。
    ejb/养老金计划
    com.wombat.emp.PensionPlan
    养老金计划
    ...
    ... 
    
  • 使用JNDI查找,但不要使用@EJB注释或EJB部署声明依赖项-完全使用您自己的逻辑处理,而不需要容器帮助。使用延迟/错误处理

  • 使用JBoss专有配置控制部署顺序:


  • 我认为最好的方法是延迟MDB的部署,直到所有EJB都启动并运行。 这基本上是上述答案中的第4个方法

    “使用JBoss专有配置控制部署顺序:


    您可以在查找调用周围实现一个带有回退的循环。

    快速想法:如果您已经事务化了消耗,您可能会拒绝
    NameNotFoundException
    上的发送,有一个合理的重试策略,并希望下次部署EJB?这很重要,但请注意,如果有数以百万计的消息在队列中等待(事实上,这就是我的情况),每个消息最初都会被处理为拒绝发送。数据库可能会屈服。无论如何,它在应用程序启动时会承受巨大的负载。你能在这里粘贴一段代码吗。。如何执行查找。您的MDB类定义是什么?您能不能不将消息持久化到队列中,以便在部署后队列将为空?考虑到你的情况,我不明白你为什么坚持这样的信息。不幸的是,我不得不这么做。这是一种财务处理,我们真的必须保留所有消息(甚至复制它们,但那是另一回事)。格伦,谢谢你的回答。这证实了没有任何严格而优雅的解决方案使用这些技术。不管怎样,还是需要某种黑客攻击。我可能会尝试3或4个选项。