使用自定义 ClassLoader 覆盖 类 的现有实现

Using a custom ClassLoader to override existing implementations of classes

首先,我知道以前有人问过这个问题,但是 none 我见过的解决方案对我有用!

为了能够用新的字节码覆盖 classes 的现有实现,我想要一个 class 加载器(设置为默认值),其中所有调用任何 class(不包括java 像“java”这样的包通过我的 loadClass/findClass 覆盖方法。从那里我可以检查一个静态注册表,看看是否有那个 class 的覆盖。我愿意尝试以不同的方式执行此操作,但到目前为止,这看起来是最快和最简单的解决方案。

我的问题是,出于某种原因,即使我将加载程序设置为 VM args(-Djava.system.class.loader=my.package.path.ProxyClassLoader) 中的默认加载程序,它也会将加载(class)抛给父级,然后,我假设将 classloader 设置为自身。这意味着所有查找或加载 classes 的调用现在都通过父级而不是我的 classloader。

此外,我想使用 JUnit 来测试它,但我无法使用自定义 classloader(使用 JUnit API 和 [=36= 中的 JUnit 引擎]) 所以我只是上了老学校并使用了一个 main(我可以在其中修改 vm 参数)。

我尝试过的事情:

  1. 将class加载器设置为线程上下文加载器。
  2. 重写加载class 以尽量不将加载交给父级,这只会导致比解决的问题多得多的问题。
  3. 尝试进行反射以更改 class 的 classloader(Java 特别不允许它 + 它会非常慢且不值得)

这是我的 classloader 原样:

public class ProxyClassLoader extends ClassLoader {
    public ProxyClassLoader(ClassLoader parent) {
        super(parent);
        Thread.currentThread().setContextClassLoader(this);

    }

    //Didn't look like i need to override anything so 
    //this is just a simplicity thing for me(i call it through other classes)
    public Class<?> defineClass(byte[] b, String name) {
        return super.defineClass(name, b, 0, b.length, defaultDomain);
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        if (ClassManager.hasOverload(name)) return ClassManager.retrieve(name);
        return super.loadClass(name, resolve);

    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        return this.loadClass(name, true);
    }
}

谢谢!

不要完全跳过超级 class 加载器。试试这样的东西?

 @Override protected Class<?> loadClass(String name, boolean resolve) throws 
     ClassNotFoundException {
            if(name belongs to java classes) {
                 return super.loadClass(name, resolve);
            }
            byte[] b = ..// read bytes from your .class files. or use getResourceAsStream(name)
            Class<?> c = defineClass(b, name);
            if(resolve) resolveClass(c);
            return c;
        }