使用自定义 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 参数)。
我尝试过的事情:
- 将class加载器设置为线程上下文加载器。
- 重写加载class 以尽量不将加载交给父级,这只会导致比解决的问题多得多的问题。
- 尝试进行反射以更改 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;
}
首先,我知道以前有人问过这个问题,但是 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 参数)。
我尝试过的事情:
- 将class加载器设置为线程上下文加载器。
- 重写加载class 以尽量不将加载交给父级,这只会导致比解决的问题多得多的问题。
- 尝试进行反射以更改 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;
}