自定义类加载器中有一种方法可以将我的类加载器附加到该类上,而我委托它来超级创建它?

问题描述 投票:0回答:1

我有这个堆栈跟踪,这是此类第一次加载(我在此类的断点处有一个条件....]]

enter image description here

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非常棘手。您有这些类型的课程

  1. 标准java.lang类
  2. Webpieces启动类
  3. 应用程序按需编译]
  4. 位于应用程序类之下和之上的Webpieces插件类
  5. 位于应用程序类之下和之上的库
  6. 对于#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

似乎可以精确地完成您想要的事情:)

java classloader
1个回答
1
投票

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());
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.