WebLogic 12c重新部署时「JNDI already in use」问题求助
WebLogic 12c二次部署EJB JNDI冲突问题排查与解决
我之前处理过好几起类似的WebLogic热部署资源泄漏导致的JNDI冲突问题,结合你描述的场景——仅部分开发者机器非确定性出现、重启服务器能临时恢复、清理缓存无效,给你几个针对性的排查和解决方向:
1. 显式指定EJB的JNDI名称,避免自动绑定冲突
默认情况下,WebLogic会为无状态EJB自动生成global JNDI名称(格式为java:global/[appName]/[moduleName]/[beanName]),但二次部署时,旧的EJB实例可能因资源泄漏未被彻底销毁,导致新实例无法绑定相同的JNDI。
解决办法:
- 通过注解指定:给
LoanTypeService添加显式的JNDI映射注解:@Stateless(mappedName = "app/loanTypeService") public class LoanTypeService { // 你的业务逻辑 } - 通过部署描述文件指定:如果不想修改代码,可以在
WEB-INF/weblogic-ejb-jar.xml中配置:<weblogic-ejb-jar xmlns="http://xmlns.oracle.com/weblogic/weblogic-ejb-jar"> <weblogic-enterprise-bean> <ejb-name>LoanTypeService</ejb-name> <jndi-name>app/loanTypeService</jndi-name> </weblogic-enterprise-bean> </weblogic-ejb-jar>
显式指定后,WebLogic会强制使用你定义的JNDI名称,避免自动生成时的冲突。
2. 排查类加载器泄漏问题
非确定性出现在3台机器,大概率和这几台机器的热部署频率、JVM内存状态有关——WebLogic的热部署机制如果遇到类加载器泄漏,旧的EJB类加载器未被GC回收,会导致旧的JNDI绑定一直存在。
排查步骤:
- 启用WebLogic的类加载器泄漏调试:在
setDomainEnv.sh(Linux)或setDomainEnv.bat(Windows)中添加以下JVM参数:
重启服务器后,观察部署日志,会输出类加载器泄漏的具体信息,比如哪些资源(线程、连接)未被释放。export JAVA_OPTIONS="$JAVA_OPTIONS -Dweblogic.debug.DebugClassLoaderLeaks=true -Dweblogic.debug.DebugClassLoader=true" - 检查这3台机器的JVM参数是否开启了
-XX:+DisableExplicitGC:如果开启了这个参数,WebLogic无法触发显式GC回收旧的类加载器,需要移除该参数。
3. 修改WebLogic部署策略,强制彻底更新
WebLogic的默认增量更新(Partial Update)可能会跳过一些资源清理步骤,导致旧实例残留。
调整部署配置:
- 登录WebLogic控制台,找到你的应用→部署→更新
- 在更新选项中,选择完全更新(Full Update),而不是“仅更新已更改的文件”
- 同时,关闭应用的**快速部署(Fast Deployment)**功能:在应用的部署设置中,找到“快速部署”选项并禁用
完全更新会彻底替换旧的应用实例,避免增量更新带来的资源残留问题。
4. 验证EJB的生命周期回调是否正常执行
如果LoanTypeService的@PreDestroy方法未正确执行,EJB实例不会被销毁,对应的JNDI绑定也不会释放。
验证步骤:
- 在
LoanTypeService中添加@PreDestroy方法并打印日志:@PreDestroy public void preDestroy() { System.out.println("LoanTypeService instance destroyed at: " + new Date()); } - 二次部署时,观察服务器日志是否输出该日志。如果没有,说明旧实例未被销毁,需要排查是否有资源持有导致实例无法被GC回收(比如未关闭的数据库连接、线程池中的活跃线程)。
错误日志详情
return (<Warning> <Deployer> <BEA-149078> <Stack trace for message 149004 weblogic.application.ModuleException: Error deploying the EJB LoanTypeService(Application: moduleName, EJBComponent: moduleName.war), the JNDI name java:global/moduleName/LoanTypeService is already in use. You must set a different JNDI name in the weblogic-ejb-jar.xml deployment descriptor or corresponding annotation for this EJB before it can be deployed. at weblogic.application.internal.ExtensibleModuleWrapper.prepare(ExtensibleModuleWrapper.java:114) at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:100) at weblogic.application.internal.flow.ModuleStateDriver$1.next(ModuleStateDriver.java:192) at weblogic.application.internal.flow.ModuleStateDriver$1.next(ModuleStateDriver.java:187) at weblogic.application.utils.StateMachineDriver$ParallelChange.run(StateMachineDriver.java:83) Truncated. see log file for complete stacktrace Caused By: Error deploying the EJB LoanTypeService(Application: moduleName, EJBComponent: moduleName.war), the JNDI name java:global/moduleName/LoanTypeService is already in use. You must set a different JNDI name in the weblogic-ejb-jar.xml deployment descriptor or corresponding annotation for this EJB before it can be deployed. at weblogic.ejb.container.deployer.SessionBeanInfoImpl.prepare(SessionBeanInfoImpl.java:502) at weblogic.ejb.container.deployer.EJBDeployer.setupBeanInfos(EJBDeployer.java:580) at weblogic.ejb.container.deployer.EJBDeployer.prepare(EJBDeployer.java:733) at weblogic.ejb.container.deployer.EjbModuleExtension.postPrepare(EjbModuleExtension.java:101) at weblogic.application.internal.ExtensibleModuleWrapper$PrepareStateChange.next(ExtensibleModuleWrapper.java:297) Truncated. see log file for complete stacktrace )
内容的提问来源于stack exchange,提问作者Theodore
相关产品推荐
相关产品推荐

