首先,我知道以前有人问过这个问题,但是我看到的解决方案都不适合我!
为了能够用新的字节码覆盖类的现有实现,我想要一个类加载器(设置为默认值),其中所有对任何类的调用(不包括java包,如"java.")都要通过我的loadClass/findClass覆盖方法。从那里我可以检查一个静态注册表,看看是否有一个覆盖的类。我愿意尝试用不同的方法来做这件事,但到目前为止,这看起来是最快最简单的解决方案。
我的问题是,由于某种原因,即使当我设置我的加载器作为虚拟机参数(-Djava.system.class.loader=my.package.path.ProxyClassLoader
)的默认值,它抛出加载(类)的父,然后,我假设设置类加载器本身。这意味着所有查找或加载类的调用现在都要通过父类而不是我的类加载器。
此外,我想使用JUnit来测试这一点,但我不能让它使用自定义类加载器(使用JUnit API与JUnit引擎在gradle),所以我只是去了老派和使用一个主(在那里我可以修改vm参数)。
我尝试过的事情:
- 设置类加载器为线程上下文加载器。
- 重写loadclass,试图不把加载抛给父类,这只会导致比它解决的更多的问题。
- 试图做反射来改变一个类的类加载器(这是Java +特别不允许的,它会非常慢,不值得)
这是我的类加载器:
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);
}
}
谢谢!
不要完全跳过超类加载器。试试这样的东西?
@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;
}