gpt4 book ai didi

java - 加载依赖于内部类的外部类

转载 作者:行者123 更新时间:2023-12-01 14:06:56 25 4
gpt4 key购买 nike

我正在尝试为 Java 编写一个简单的插件架构(它扩展了我们现有的一些功能,这就是为什么我没有使用合适的插件库)

我的 war 中有一个基类(使用 JBoss 部署):

package org.example.components;

public abstract class ComponentBase {
// Base code
}

我有一个 jar custom-components.jar ,其中包含一些自定义组件代码:

package org.example.components.custom;

public class CustomComponent extends ComponentBase {
// Custom code
}

通过一些魔法,我的 war 中的插件代码获取了 CustomComponent 类的名称,并执行以下操作:

Class classToRegister = Class.forName("org.example.components.custom.CustomComponent");

但是,这会抛出 NoClassDefFoundError,表示找不到 org.example.components.ComponentBase

Caused by: java.lang.NoClassDefFoundError: org/example/components/ComponentBase
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.jboss.mx.loading.RepositoryClassLoader.findClassLocally(RepositoryClassLoader.java:690)
at org.jboss.mx.loading.RepositoryClassLoader.findClass(RepositoryClassLoader.java:670)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at org.jboss.mx.loading.RepositoryClassLoader.loadClassLocally(RepositoryClassLoader.java:200)
at org.jboss.mx.loading.ClassLoadingTask$ThreadTask.run(ClassLoadingTask.java:131)
at org.jboss.mx.loading.LoadMgr3.nextTask(LoadMgr3.java:399)
at org.jboss.mx.loading.RepositoryClassLoader.loadClassImpl(RepositoryClassLoader.java:527)
at org.jboss.mx.loading.RepositoryClassLoader.loadClass(RepositoryClassLoader.java:415)
at java.lang.ClassLoader.loadClass(ClassLoader.java:295)
at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:627)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1345)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1204)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
... 259 more
Caused by: java.lang.ClassNotFoundException: No ClassLoaders found for: org/example/components/ComponentBase
at org.jboss.mx.loading.LoadMgr3.beginLoadTask(LoadMgr3.java:212)
at org.jboss.mx.loading.RepositoryClassLoader.loadClassImpl(RepositoryClassLoader.java:521)
at org.jboss.mx.loading.RepositoryClassLoader.loadClass(RepositoryClassLoader.java:415)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 297 more

ComponentBase 已加载正常,因为我可以毫无错误地执行 Class.forName('org.example.components.ComponentBase') 。初始化 CustomComponent 时是否使用不同的类加载器?我尝试显式传递类加载器,但遇到了相同的错误。

最佳答案

由于您的插件基类位于 WAR 文件中(大概在 WEB-INF/classes/... 中),因此您需要从 上的某个位置删除 custom-components.jar classpath 并将其移至您的 war 文件的“WEB-INF/lib”文件夹中。

这样两个类都由同一个类加载器加载。

当你执行时,你现在拥有它的方式:

Class.forName('org.example.components.ComponentBase')

它成功了,因为您正在将 ComponentBase 加载到您的 war 类加载器中。 forName方法首先检查war的WEB-INF/lib和WEB-INF/classes并找到它。

但是当你执行时

Class.forName("org.example.components.custom.CustomComponent");

war 类加载器首先像以前一样检查 WEB-INF/lib、WEB-INF/classes,但没有在那里找到它。然后它开始询问“父”类加载器。父类加载器(可能是 JBoss 特定的类加载器,或者引导类加载器?)找到该类并尝试加载它。

一切顺利,直到检测到 CustomComponent 扩展了 BaseComponent。因此父类加载器尝试加载 BaseComponent。然而,父类加载器无法找到 BaseComponent,因为不允许它在您的 war 文件中查找。你的 war 类加载器是一个子类加载器,类加载器只能委托(delegate)给父类加载器。

考虑一下如果您取消部署 war 并且您的基类消失了会发生什么。或者,如果您部署了两场 war ,都与您的基类有关。引导类路径上的插件类依赖于可能消失或倍增的基类的想法是没有意义的。

现在,只需将所有代码放入 WAR 文件中,并保持类加载逻辑尽可能简单。

关于java - 加载依赖于内部类的外部类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18834357/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com