简体   繁体   English

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

[英]Loading external classes that depend on internal classes

I am trying to write a simple plugin architecture for Java (it is extending some existing functionality we have, which is why I'm not using a proper plugin library) 我正在尝试为Java写一个简单的插件架构(它扩展了我们现有的某些功能,这就是为什么我没有使用适当的插件库的原因)

I have a base class in my war (deployed using JBoss): 我在战争中有一个基类(使用JBoss部署):

package org.example.components;

public abstract class ComponentBase {
    // Base code
}

I have a jar custom-components.jar containing some custom component code: 我有一个jar custom-components.jar其中包含一些自定义组件代码:

package org.example.components.custom;

public class CustomComponent extends ComponentBase {
    // Custom code
}

Through some magic the plugin code in my war gets the name of the CustomComponent class and does: 通过一些魔术,我的战争中的插件代码获得了CustomComponent类的名称并执行以下操作:

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

However, this throws a NoClassDefFoundError , saying it can't find org.example.components.ComponentBase . 但是,这引发了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 has loaded fine, because I can do Class.forName('org.example.components.ComponentBase') without error. ComponentBase已加载良好,因为我可以执行Class.forName('org.example.components.ComponentBase')而不会出现错误。 Is it using a different class loader when initializing CustomComponent ? 初始化CustomComponent时是否使用其他类加载器? I tried explicitly passing in a class loader but I got the same error. 我尝试显式传递类加载器,但出现相同的错误。

Since your plugin base class is in your WAR file (presumably in in WEB-INF/classes/...) you need to remove custom-components.jar from somewhere on the classpath and move it into the 'WEB-INF/lib' folder of your war file. 由于您的插件基类位于WAR文件中(可能位于WEB-INF / classes / ...中),因此您需要从somewhere on the classpath删除custom-components.jar并将其移至“ WEB-INF / lib”中您的war文件的文件夹。

This way both classes are loaded by the same class loader. 这样,两个类都由同一个类加载器加载。

The way you have it now, when you execute: 执行时现在拥有的方式:

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

it succeeds because you are loading ComponentBase into your war classloader. 它成功,因为您正在将ComponentBase加载到战争类加载器中。 The forName method first checks the war's WEB-INF/lib and WEB-INF/classes and finds it. forName方法首先检查战争的WEB-INF / lib和WEB-INF / classs并找到它。

However when you execute 但是,当您执行

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

the war classloader first checks WEB-INF/lib, WEB-INF/classes as before but does not find it there. 战争类加载器首先像以前一样检查WEB-INF / lib,WEB-INF / class,但在那里找不到它。 Then it starts asking the "parent" classloader. 然后,它开始询问“父”类加载器。 The parent classloader (maybe a JBoss specific classloader, or the boot classloader?) finds the class and attempts to load it. 父类加载器(可能是JBoss特定的类加载器,还是引导类加载器?)找到该类并尝试加载它。

All goes well until it detects that CustomComponent extends BaseComponent. 一切正常,直到它检测到CustomComponent扩展了BaseComponent。 So the parent classloader attempts to load BaseComponent. 因此,父类加载器尝试加载BaseComponent。 However the parent classloader cannot find BaseComponent because it is not allowed to look in your war file. 但是,父类加载器找不到BaseComponent,因为不允许在war文件中查找它。 You war classloader is a child classloader and classloaders can only delegate to parent class loaders. 您战争类加载器是子类加载器,并且类加载器只能委托给父类加载器。

Consider what would happen if you undeployed your war and your base class went away. 考虑一下如果您取消部署战争而您的基础阶级走了会发生什么。 Or if you deployed two wars, both with your base class. 或者,如果您部署了两次战争,都与您的基类一起进行。 The idea of a plugin class on the boot class path depending on a base class that might vanish or multiply would make no sense. 在启动类路径上依赖于可能消失或成倍增加的基类的插件类的想法是没有意义的。

For now, just put all the code in your WAR file and keep the classloading logic as simple as possible. 现在,只需将所有代码放在WAR文件中,并使类加载逻辑尽可能简单即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM