使用EJB客户端JAR时遭遇java.lang.NoClassDefFoundError问题求助
这个NoClassDefFoundError的核心原因是EJB调用返回的对象在客户端反序列化时,需要依赖core/common/business/Code类,但你的core.external.ejb.client.jar里没有包含这个类。
虽然你的项目没有直接引用Code类,但从错误栈可以看到,反序列化流程(ObjectInputStream处理返回对象时)触发了对Code类的加载——大概率是以下两种情况:
Application类(或它内部包含的集合、关联对象)中存在Code类型的字段,或者在序列化/反序列化的回调方法(比如readObject)里间接用到了Code类;- 服务器端
findApp()方法中创建的Services实例,其内部持有Code类的引用,并且这个引用没有被标记为transient,导致序列化返回对象时,把Services(或关联的Code依赖)也纳入了序列化对象图,客户端反序列化时就需要加载Code类。
针对这个问题,你可以按以下步骤处理:
补充缺失的类到客户端Jar
把core/common/business/Code.class添加到你的core.external.ejb.client.jar中。因为EJB客户端需要完整的类来完成反序列化,哪怕你的代码没有直接调用这个类,反序列化机制也会要求它存在于classpath中。排查序列化对象图的不必要依赖
检查服务器端的Services类,如果其中的Code字段只是服务器端内部使用,不需要传递到客户端,那么可以给这个字段加上transient修饰符,这样序列化时就不会把这个字段包含进去,客户端也就不需要加载Code类了。验证返回对象的依赖链
梳理findApp()返回的Application对象的整个依赖树,确保所有出现在对象图中的类都被包含在core.external.ejb.client.jar里。可以用javap命令或者序列化分析工具来查看Application类的序列化字段,确认是否有隐藏的Code依赖。
EJB的远程调用本质是对象的序列化/反序列化,客户端classpath必须包含所有参与序列化的类,这和是否直接引用没有关系——哪怕是间接依赖的类,只要在序列化对象图里,就必须存在。这也是为什么其他项目用完整的core.ejb.client.jar不会出问题,因为里面包含了所有必要的依赖类。
内容的提问来源于stack exchange,提问作者Ada

