所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

EJB3.0部署消息驱动Bean抛javax.naming.NameNotFoundException异常原因及解决方法

EJB3.0部署消息驱动Bean抛javax.naming.NameNotFoundException异常原因及解决方法 一

文章目录CloseOpen

先搞懂:这个异常到底在说什么?

其实不用怕专业术语,JNDI本质就是个“资源通讯录”:你要让MDB接收消息,得先告诉服务器“我要找的JMS队列/主题叫什么名字”,服务器去“通讯录”(JNDI树)里查,没查到就扔这个异常。但问题从来不是“通讯录里没有”,而是“你写的名字和通讯录里的不一样”,或者“你压根没把资源放进通讯录”

我朋友当时的情况就是后者——他在ejb-jar.xml里写了jms/OrderQueue,但服务器启动时压根没加载这个配置,因为文件放错了地方。你想,通讯录都没更新,服务器怎么可能查到?后来他把ejb-jar.xml移到META-INF,重启服务器,异常直接消失——就这么个路径错误,折腾了一上午。

最常见的4个原因,我帮你排好优先级了

我后来遇到过10次类似问题, 下来,90%的情况逃不出这4个原因——按“出现概率”排序,你可以先查前两个,大概率能解决。

  • 第一个坑:JNDI名称的“前缀/后缀”加错了
  • 不同应用服务器的JNDI名称默认规则不一样,比如JBoss要加java:/前缀,WebLogic是jms/,GlassFish是java:app/——你加错或漏加,服务器就“不认”。

    我自己踩过这个坑:前年用WebLogic部署MDB,把JNDI名称写成java:/jms/OrderQueue,结果直接报错。后来查Oracle官方文档(Oracle WebLogic Server 12c文档明确说:“JMS资源的JNDI名称通常以jms/开头,无需额外添加java:前缀”),才知道WebLogic的JNDI名称不需要java:/。改了之后,一秒启动成功。

    给你整理了个常见服务器的前缀表格,直接对照着改:

    应用服务器 JMS资源默认前缀 示例JNDI名称
    JBoss EAP 6+ java:/ java:/jms/OrderQueue
    WebLogic 12c+ jms/ jms/OrderQueue
    GlassFish 3+ java:app/ java:app/jms/OrderQueue

    比如你用WebLogic,就别加java:/;用JBoss,就必须加——省得猜来猜去。

  • 第二个坑:配置文件“位置不对”,服务器没加载
  • ejb-jar.xml、persistence.xml这些配置文件,必须放在正确的目录,否则服务器根本“看不到”:

  • ejb-jar.xml → 必须在META-INF目录下(不是WEB-INF!不是src/main/resources!);
  • persistence.xml → 如果用到数据源,要放在META-INFWEB-INF/classes/META-INF(Maven项目通常是src/main/resources/META-INF)。
  • 我遇到过一个极端案例:一个做电商的朋友,把ejb-jar.xml放在了src/main/java下——Maven打包时根本没把它放进WAR包,服务器启动时自然没加载。后来在pom.xml里加了资源复制配置(把src/main/java下的ejb-jar.xml复制到META-INF),才解决问题:

    
    

    src/main/java

    /ejb-jar.xml

    META-INF

  • 第三个坑:服务器“没绑定”你要的资源
  • 简单说:你在代码里写了jms/OrderQueue,但服务器里根本没创建这个JMS队列

    我帮物流系统的朋友排查过这种情况:他日志里的missing name是jms/OrderQueue,但登录WebLogic控制台的JNDI树一看,只有OrderQueue——原来他创建队列时,JNDI名称没加jms/前缀。代码里的名称是jms/OrderQueue,服务器里的是OrderQueue,能找到才怪?后来他把队列的JNDI名称改成jms/OrderQueue,重启服务器,异常直接消失。

  • 第四个坑:依赖包缺了,JNDI上下文没初始化
  • EJB3.0的MDB依赖javax.ejb-apijavax.jms-api这两个包,如果你的项目里没引,或者scope设错了(比如设成provided但服务器里没有),服务器启动时无法初始化JNDI上下文,直接抛异常。

    我之前用Maven构建项目时,把jms-api的scope设成了provided,结果本地运行时没引入这个包,服务器启动时抛NameNotFoundException。后来把scope改成compile(让Maven把包打进WAR),问题解决。你可以检查下pom.xml里的依赖:

    <!-
  • 正确的依赖配置 >
  • javax.ejb

    javax.ejb-api

    3.2

    compile <!-

  • 不要用provided >
  • javax.jms

    javax.jms-api

    2.0.1

    compile

    排查的万能步骤:按顺序来,别乱

    如果上面4个原因都没解决,按这个步骤来,10分钟内找到问题:

    第一步:先看日志里的“missing name”

    日志里会明确写“Name [XXXX] not found”,把XXXX复制出来(比如jms/OrderQueue),然后去服务器的JNDI浏览器查:

  • JBoss:用JMX Console(路径http://localhost:9990/console)→ 找到“JNDI View”;
  • WebLogic:控制台→ 领域→ 服务→ JNDI树→ 搜索XXXX;
  • GlassFish:控制台→ 资源→ JNDI浏览。
  • 如果JNDI树里没有XXXX,说明服务器没绑定这个资源;如果有,说明你的代码或配置文件里的名称写错了。

    第二步:用“笨办法”对比所有名称

    把所有涉及JNDI名称的地方复制到一个文本文件,逐行对比:

  • 服务器里的JNDI名称(比如jms/OrderQueue);
  • ejb-jar.xml里的(比如jms/OrderQueue);
  • MDB注解里的mappedName(比如@MessageDriven(mappedName = "jms/OrderQueue"));
  • 客户端代码里的lookup名称(比如ctx.lookup("jms/OrderQueue"))。
  • 只要有一个不一样,直接标红——我用这个办法解决过80%的问题,比如去年帮朋友排查时,发现他把jms/OrderQueue写成了jms/OrderQueque(多了个u),肉眼根本看不出来,复制到文本里才发现。

    第三步:写个客户端测试,排除服务器问题

    用Java代码写个简单的JNDI客户端,直接连接服务器查资源:

    import javax.naming.Context;
    

    import javax.naming.InitialContext;

    import java.util.Properties;

    public class JndiTest {

    public static void main(String[] args) throws Exception {

    Properties props = new Properties();

    // 按你的服务器配置改

    props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");

    props.setProperty(Context.PROVIDER_URL, "remote://localhost:4447");

    props.setProperty(Context.SECURITY_PRINCIPAL, "admin");

    props.setProperty(Context.SECURITY_CREDENTIALS, "admin");

    Context ctx = new InitialContext(props);

    // 替换成你要查的JNDI名称

    Object resource = ctx.lookup("java:/jms/OrderQueue");

    System.out.println("找到资源:" + resource.getClass().getName());

    }

    }

    如果这个客户端抛同样的异常,说明是服务器配置的问题;如果能拿到资源,说明是MDB的配置有问题(比如注解里的名称写错了)。

    其实这个异常看着吓人,本质就是“名称对不上”或“资源没注册”**——你按上面的步骤一步步来,肯定能找到问题。对了,如果你排查时遇到了奇怪的情况(比如服务器里有这个JNDI名称,但MDB就是找不到),欢迎回来留言告诉我,我帮你一起想想办法!


    我之前遇到过好几次MDB注解和ejb-jar.xml里的JNDI名称撞车的情况——有次朋友做电商订单系统,注解里明明写了@MessageDriven(mappedName="jms/OrderQueue"),结果ejb-jar.xml里不小心多打了个s,写成jms/OrderQueues。服务器启动时没报任何错,但MDB就是收不到消息,查了半天才发现,服务器实际用的是ejb-jar里的名称,注解里的直接被覆盖了—— 服务器加载配置是有顺序的,先读ejb-jar.xml这种“专门的EJB配置文件”,再处理类上的注解,相当于ejb-jar里的内容是“最终确认版”,注解里的就算写对了,也会被盖过去。

    其实解决起来特别简单,最省心的办法就是把两边的名称完全对齐——注解里写jms/OrderQueue,ejb-jar.xml里也写同一个名字,别自己给自己挖坑。我帮做库存系统的朋友调过类似问题,他注解里写对了jms/StockQueue,但ejb-jar里错写成jms/StocksQueue,结果MDB一直连不上队列,改对ejb-jar里的名称重启就好了。要是真遇到老项目要兼容、必须调整优先级的情况,有些服务器(比如JBoss)能改配置让注解生效,但我 优先动ejb-jar.xml——毕竟这个文件是专门管EJB配置的,比注解更“稳”,不容易出奇怪的问题。你要是拿不准哪边生效,直接看服务器启动日志里的“JNDI binding”记录,里面会明明白白写着MDB最终用的是哪个名称,一查就清楚。

    还有次更无语的情况,朋友的项目里注解和ejb-jar的名称都对,但服务器就是用了错的——后来发现是ejb-jar.xml放错了目录,服务器没加载到,结果注解里的名称没被覆盖,但他以为ejb-jar生效了,折腾了半天。所以真遇到冲突,先确认ejb-jar的位置对不对(必须在META-INF里),再把两边的名称对齐,要是还不行,就去日志里找“JNDI binding”的记录,基本就能定位问题——其实哪有什么复杂的原理,就是“谁后加载谁算”的事儿,ejb-jar先加载,自然它说了算。


    不同应用服务器的JNDI名称前缀有什么区别?

    不同服务器的JNDI名称默认规则不同:JBoss需要加java:/前缀(如java:/jms/OrderQueue);WebLogic以jms/开头(如jms/OrderQueue);GlassFish常用java:app/前缀(如java:app/jms/OrderQueue)。 参考对应服务器的官方文档确认规则。

    ejb-jar.xml的正确位置在哪里?

    ejb-jar.xml必须放在META-INF目录下(Maven项目通常是src/main/resources/META-INF),不能放在WEB-INF或src/main/java等目录,否则服务器无法加载配置。

    写JNDI客户端测试有什么用?

    客户端测试可以快速区分问题根源:如果客户端能通过JNDI lookup找到资源,说明服务器配置没问题,问题在MDB自身(如注解名称写错);如果客户端也找不到,说明是服务器资源未绑定或配置错误。

    MDB注解和ejb-jar.xml的JNDI名称冲突了怎么办?

    通常ejb-jar.xml的配置会覆盖MDB注解(如@MessageDriven的mappedName属性)。 保持两者名称一致,避免混淆;如果需要调整优先级,可优先修改ejb-jar.xml的配置。

    JNDI树里能查到资源,但MDB还是报错怎么办?

    先检查名称大小写(部分服务器如WebLogic区分大小写),再重启服务器清除缓存;也可确认MDB是否使用了java:comp/env/前缀(如java:comp/env/jms/OrderQueue),需确保与JNDI树中的名称完全匹配。

    原文链接:https://www.mayiym.com/47296.html,转载请注明出处。
    0
    显示验证码
    没有账号?注册  忘记密码?

    社交账号快速登录

    微信扫一扫关注
    如已关注,请回复“登录”二字获取验证码