我有这个堆栈跟踪,这是此类第一次加载(我在此类的断点处有一个条件....]]
CompilingClassLoader是我的(即此https://github.com/deanhiller/webpieces/blob/master/core/runtimecompile/src/main/java/org/webpieces/compiler/impl/CompilingClassloader.java]
我希望此类以plugin.getClass.getClassLoader返回的方式返回CompilingClassLoader。相反,它的类加载器是AppClassLoader
这为插件开发人员造成了许多问题,因为当前的解决方法是线程上下文类加载器。是否有办法声明编译的类加载器已加载但委托超级类加载器?
CRITICAL行是上面链接中的111行。我希望该行使用超类为我创建类,但我希望它看起来像我创建的类。即。当调用clazz.getClassLoader()时,返回的类应返回“ my”类加载器。然后解决了很多问题。
EDIT ---------------------------------------
经过进一步调查。 CompilingClassLoader非常棘手。您有这些类型的课程
- 标准java.lang类
- Webpieces启动类
- 应用程序按需编译]
- 位于应用程序类之下和之上的Webpieces插件类
- 位于应用程序类之下和之上的库
对于#1,一旦我打到main,许多这样的东西(如java.lang.Object)就由应用程序类加载器加载,因此必须始终保持为真,以免使人恐惧的将X转换为X会产生ClassCastException]
对于#2,其中大多数都在启动时也由应用程序类加载器加载
对于#3,这是我们编译或重新编译的代码。要重新编译,我们丢弃CompilingClassLoader并重新创建所有以前未更改的类的另一个BUT缓存字节。
对于#4和#5,这真的很棘手!!!我们有一个ProdServerMeta(一个应用程序编译的类),它引用Webpieces中的插件,然后这些插件有时会加载需要在更改时进行编译的其他应用程序类。当前,我们在编译类加载器中注入了休眠以避免问题。
我想得更多,现在休眠类由应用程序类加载器加载,因为当我们无法编译委托给父类的类时,我们返回null。
现在,我遇到了CompilingClassLoader遇到这些情况,很难将其简化为像下面的Jan-Willem Gmelig Meyling的类加载器那样的类加载器!主要是因为在该示例中defineClass似乎很关键并且缺失(并且像下面的Olivier所说的那样非常重要)。
无论如何,我尝试下面的类加载器遇到了这些问题
- java.lang。*的加载导致SecurityException,所以我不得不委托它
- 解决之后,当slf4j尝试加载配置时,我从SAXParserFactoryImpl到SAXParserFactoryImpl遇到了ClassCastException
由于服务器.main创建了Logger,然后创建Logger的所有其他类都在CompilingClassLoader中创建了第二个类,因此这完全有意义。这导致我遇到这样的情况:
我无法加载在加载应用程序之前加载的任何内容
[接下来,作为客户的网络服务器,我也无法确定应用加载前与应用加载后所引用的内容。
我得出的结论是,没有解决方案,因为当开发人员编写代码时,我丢弃了以前的类加载器,因此许多类必须继续存在,例如Logger,它在启动时被AppClassLoader引用。
当然,如果我使用CompilingClassLoader进行启动,那么我可能会更好地机会尝试加载除java.lang之外的所有内容,但是在服务器启动后,我仍然会遇到一些代码问题总是被FIRST CompilingClassLoader引用,而以后的重新编译代码将指向新的CompilingClassLoader。
我认为,唯一的解决方法是,在这种情况下,我认为插件必须使用ContextClassLoader,并且下面的Olivier不可能正确。
谢谢,院长
我有这个堆栈跟踪,这是此类的第一次加载(我在此类的断点上有一个条件)...。CompilingClassLoader是我的(即,这个https://github.com/。 ..
Classloaders首先从其父类加载器加载类。您应该可以解决此问题,只需不为类加载器设置父类加载器,然后亲自委托对loadClass
的调用即可。
一个工作示例:
public class SomeClass implements Runnable {
@Override
public void run() {
System.out.println("Class loader for class: " + getClass().getClassLoader());
System.out.println("Class loader for thread: " + Thread.currentThread().getContextClassLoader());
System.out.println("Class loader for transitive dependency: " + SomeDependency.class.getClassLoader());
}
}
传递依赖:
public class SomeDependency {}
测试和类加载器:
import java.net.URL;
import java.net.URLClassLoader;
public class Test {
public static class CustomClassLoader extends URLClassLoader {
ClassLoader delegate;
public CustomClassLoader(URL[] urls, ClassLoader parent) {
super(urls, null);
delegate = parent;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
return super.loadClass(name);
} catch (ClassNotFoundException e) {
return delegate.loadClass(name);
}
}
}
public static void main(String... args) throws Exception {
URL location = SomeClass.class.getProtectionDomain().getCodeSource().getLocation();
CustomClassLoader customClassLoader = new CustomClassLoader(new URL[] { location }, ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(customClassLoader);
Class<?> aClass = customClassLoader.loadClass("com.pkg.SomeClass");
Runnable runnable = (Runnable) aClass.newInstance();
runnable.run();
}
}
输出:
Class loader for class: com.pkg.Test$CustomClassLoader@4e50df2e
Class loader for thread: com.pkg.Test$CustomClassLoader@4e50df2e
Class loader for transitive dependency: sun.misc.Launcher$AppClassLoader@18b4aac2
似乎可以精确地完成您想要的事情:)