Tomcat通过HTTP调用Payara远程EJB抛出NameNotFoundException问题
Payara 5.2022.2 远程EJB HTTP调用NameNotFoundException排查解决
问题场景
在Payara Server 5.2022.2中部署打包在JULY.ear内的TestMC EJB应用,EJB代码定义如下:
@Remote public interface City { public Integer getVisits(); }
@Stateless(name = "City") public class CityEJB implements City, Serializable { }
启用ejb-invoker组件执行命令:
asadmin > set-ejb-invoker-configuration --enabled=true
部署后控制台输出可移植JNDI名称:
Portable JNDI names for EJB City: [java:global/JULY/TestMC/City, java:global/JULY/TestMC/City!cityall.City]
Tomcat 9侧客户端使用ejb-http-client依赖编写InitialContext查找逻辑,依赖配置:
<dependency> <groupId>fish.payara.extras</groupId> <artifactId>ejb-http-client</artifactId> <version>5.2022.2</version> </dependency>
InitialContext配置:
public class InitialContextUtil { protected static InitialContext ic; public static InitialContext getInstance() { if (ic == null) { final Properties initialContextProperties = new Properties(); initialContextProperties.put(Context.INITIAL_CONTEXT_FACTORY, "fish.payara.ejb.rest.client.RemoteEJBContextFactory"); initialContextProperties.put(Context.PROVIDER_URL, "http://localhost:8080/ejb-invoker"); try { ic = new InitialContext(initialContextProperties); } catch (NamingException e) { e.printStackTrace(); } } return ic; } }
查找逻辑:
public void getUserServices() { try { cityRemote = (City) InitialContextUtil.getInstance().lookup( "java:global/JULY/TestMC/City"); } catch (NamingException e) { e.printStackTrace(); } }
执行时抛出异常:
javax.naming.NameNotFoundException: Name [global/JULY/TestMC/City] is not bound in this context.
环境为Eclipse 2022-06、JDK 11,脱离IDE直接启动服务仍复现问题。
解决步骤
按优先级依次排查修复:
- 修正ejb-invoker访问路径
当前配置的PROVIDER_URL路径错误,Payara的ejb-invoker组件部署后的默认上下文根为/__ejb-invoker(注意前缀是两个下划线,和管理控制台中显示的应用名__ejb-invoker一致),将配置修改为:
修改后可以先直接在浏览器访问initialContextProperties.put(Context.PROVIDER_URL, "http://localhost:8080/__ejb-invoker");http://localhost:8080/__ejb-invoker,确认返回ejb-invoker服务响应而非404,再进行代码调试。 - 优先使用带接口全限定名的JNDI路径查找
不带接口全限定名的JNDI写法在EJB实现多接口时容易出现绑定匹配失败问题,将lookup的名称替换为带接口全路径的格式,不需要额外加java:前缀:cityRemote = (City) InitialContextUtil.getInstance().lookup( "global/JULY/TestMC/City!cityall.City"); - 补全JDK 11环境缺失的JAXB依赖
JDK 11移除了默认内置的JAXB API,ejb-http-client在序列化/反序列化EJB代理对象时依赖JAXB组件,缺失时会出现隐性的上下文加载失败,最终表现为JNDI名称找不到。在Tomcat侧Web应用的pom.xml中补充以下依赖:<dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>2.3.3</version> </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.3.9</version> </dependency> - 校验接口一致性
确认Tomcat侧Web应用中引用的City远程接口,和Payara服务端部署的City接口的全限定名(包名+类名)、方法签名完全一致,不要出现类版本、包名不匹配的问题。 - 配置生效检查
执行set-ejb-invoker-configuration命令后需要重启Payara对应域或实例,配置才会完全生效,若以上修改后仍报错,重启Payara服务后重试。
该问题和Eclipse版本、JDK大版本无直接关联,不需要降级到JDK 8或旧版Eclipse即可在JDK 11环境下正常运行。
内容的提问来源于stack exchange,提问作者Mari Carmen
相关产品推荐
相关产品推荐

