java - 尝试加载类时出现 NoClassDefFoundError

标签 java maven jakarta-ee jar drools

我收到了 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 .

我正在使用 glassfishJ2EEmaven我是 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/

相关文章:

java - 从 1.9 到 2.0.3 缺少 Liquibase 类

maven - 从 OS 系列中选择 maven 配置文件

java - EJB 与 CDI bean 中套接字客户端的最佳实践

java - 如何从远程主机访问 Glassfish V3 管理控制台网站

java - 如何在java中处理未知类型的json响应

java - Getter/Setter 和其他数据对象类之间的区别

java - EJB 3.1 的 Maven 依赖性 [jboss-ejb-api_3.1_spec]

java - 主项目 maven 中的 jar 文件未更新

xml - 在 JSP 文件中导入带有 JSTL 核心的 XML 文件时,请求的资源不可用

java - iPhone 应用程序中的 3DES 加密总是产生与 Java 中的 3DES 加密不同的结果