我收到了 java.lang.NoClassDefFoundError
尝试实例化某个类时
我将尝试简化我的项目的结构:我有 2 个 jar 文件 A(内部带有 a.class)和 B(带有 b.class)我正在尝试在“a”代码中实例化一个“b”类。 JAR A
取决于 JAR B
. JAR A
是一个常规 JAR 文件,位于 application/lib 和 JAR B
包装为 EJB_JAR
.
我正在使用 glassfish
和 J2EE
与 maven
我是 J2EE 的新手,我已经尝试过查找它。我发现这可能是一个类加载器问题,因为从 lib (A) 加载类的类加载器是加载 EAR WAR 和 EJB_JAR 的类加载器的祖先,因此由于可见性问题,我无法从“a”加载“b”类'
另外,当我尝试调用时(使用“表达式评估器”)Class.forName("com.package.SomeClass")
在从位于 Jar-A 中的类到加载 JAR-A 中的类的调试器中,我得到一个类,但是当我尝试加载位于 Jar-B 中的类时,我得到 java.lang.NoClassDefFoundError
异常(exception)。
问题是,构造函数中传递的 EJB 具有正确的所有 EJB 字段,所以我认为它应该可以工作,并且一切都编译成功。
我该如何解决这个问题?
最奇怪的事:
我正在使用位于 JAR_A 中的流口水,而 JAR_A 有一些常规类,它试图调用 b.class(在 JAR_B 中)
从 a.class 调用 b.class 不起作用,
但是直接从规则调用 b.class(从 CommandFactory.newSetGlobal("Bclass",b) 获得 b.class)工作得很好。
怎么会这样?
当我将它作为 JAR_B 中的对象传递时,它可以正常工作并调用。
最佳答案
回顾
你说:
I am trying to instantiate a 'b' class inside 'a' code. JAR A is dependant on JAR B. JAR A is a regular JAR file which is located in
application/lib
and JAR B is packaged as an EJB_JAR.
据我了解,您有一个
pom.xml
构建 jar A,声明 jar B 是它的 <dependency/>
.然后我看到您的部署方案有两种可能的情况:您要么将 jar 作为 EAR 部署到应用程序服务器,其中 jar A 作为库包含在此 EAR 中,而 jar B 是其中的部署,或者您正在尝试从另一个不相关的应用程序中使用 B。
在任何一种部署情况下,这都是一个错误,但这可能是由于错误地表达了您的依赖关系,或者错误地访问了 EJB。
嵌套部署案例
如果这是一个嵌套部署,其中 jar A 作为库包含在 EAR 中,则存在依赖关系表达式问题。 EAR 库不能依赖于 EAR 本身,它只能是相反的方式。毕竟,这是库的定义,对吧? :)
您必须重构您的应用程序以匹配您在此处尝试实现的用例。欲了解更多信息,请参阅优秀的 Patterns of Modular Architecture引用卡来自 DZone .
应用客户案例
如果您正在编写的是一个隔离的(甚至可能是独立的)客户端,它将调用 EJB 上的某些操作,那么您应该做的是创建一个接口(interface)(本地或远程,取决于您如何部署客户端)和将它与客户端应用程序和您的 EJB 一起打包。
然后在您的客户端应用程序中使用 JNDI 查找来获取对远程 EJB 的引用并通过接口(interface)使用它:
Context foo = new InitialContext(remoteJndiServiceProperties);
MyBeanInterface bar = (MyBeanInterface)foo.lookup("com.mycompany.MyBeanInterface");
bar.doStuff();
当然,必须正确表达远程 JNDI 注册属性和 bean 的业务接口(interface)名称。见EJB FAQ for Glassfish了解更多信息。
如果您的客户端在同一个部署单元中运行,则更简单 - 您只需使用
@EJB
在这种情况下注解并注入(inject)无接口(interface) EJB 引用。有关使用 GlassFish 的独立客户端的更多信息,请参阅 Developing Application Clients with ACC指南涵盖了所有可能的部署方案。
这背后的一些理论
在调试器中运行应用程序(或查看在您的客户端调用 EJB 上的方法时获取的堆转储,将对象作为参数传递给它)。
您将看到的是,EJB 容器(即您的 EJB)并未与您认为的实际类一起工作,而是与容器动态生成的称为静态代理类的东西一起工作。
因此,当您调用
instanceof
EJB 中的运算符,检查您正在使用的类是否是正确的类型,它将评估为 true
,但是当你尝试对它进行类型转换时,你会得到一个 ClassCastException
.这是 EJB 规范所要求的,您对此无能为力,除了不将对象作为引用传递,而是作为序列化数据传递(这将花费您)。
它也可以反过来工作,因为容器必须能够拦截从外部对 EJB 所做的任何事情,并使用react(例如未经授权使用受限方法、事务处理等)。
顺便说一句,你上面描述的很多内容都是非法的。 ;)
使用
Class.forName()
手动加载类例如,在 EJB 容器内 - EJB 容器应该管理对象的生命周期,以及使用工厂方法无法获得的任何东西,或者更好的是,使用“兼容”机制(如 CDI 生产者和依赖注入(inject))获得的任何东西都应该传递给您的 EJB 作为参数。同样值得怀疑的是您尝试将 EJB 实例传递给在容器外运行的应用程序的方式。如果您需要访问您的 EJB 以调用它们的方法,您应该通过 EJB 客户端来完成,在您的情况下,很可能是通过远程接口(interface)。
此外,如果您仍想继续您的方法,请查看类加载器 hell 的定义 - 您可能希望从 this article 开始。 ,但我想它和其他任何东西一样好。
关于java - 尝试加载类时出现 NoClassDefFoundError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35016551/