使用自定义ClassLoader覆盖类的现有实现 [英] Using a custom ClassLoader to override existing implementations of classes
问题描述
首先,我知道这个问题已经被问过了,但是我所见过的解决方案都没有对我有用!
First off, I know this question has been asked before, but none of the solutions i have seen worked for me!
为了能够使用新的字节码覆盖类的现有实现,我想要一个类加载器(默认设置),其中任何类的所有调用(不包括诸如"java"之类的Java包)都通过我的loadClass/findClass重写的方法.从那里,我可以检查静态注册表,以查看是否有该类的替代.我愿意尝试不同的方法,但是到目前为止,这看起来是最快,最简单的解决方案.
In order to be able to override existing implementations of classes with new bytecode I want a class loader(set as default) where all calls for any class(excluding java packages like "java.") go through my loadClass/findClass overridden methods. From there i can check a static registry to see if there is a override for that class. I am willing to try to do this differently, but so far this looks like the fastest and easiest solution.
我的问题是,即使出于某种原因,即使我在VM args( -Djava.system.class.loader = my.package.path.ProxyClassLoader
)中将加载程序设置为默认值,也会抛出将(类的)加载到父类,然后,我假设将类加载器设置为其自身.这意味着所有查找或加载类的调用现在都通过父类而不是我的类加载器进行.
My issue is that for some reason even when I set my loader as the default in VM args(-Djava.system.class.loader=my.package.path.ProxyClassLoader
) It throws the loading(of a class) to the parent which then, I assume sets the classloader to itself. This means all calls to find or load classes now go through the parent instead of my classloader.
此外,我想使用JUnit对此进行测试,但我无法使用自定义的类加载器(在Gradle中将JUnit API与JUnit Engine结合使用),所以我刚上了老学校,并使用了main(其中可以修改vm参数).
Additionally, i would like to use JUnit to test this, but i couldnt get it to use a custom classloader(Using the JUnit API with the JUnit Engine in gradle) so i just went old school and used a main(where i can modifier vm arguments).
我尝试过的事情:
- 将类加载器设置为线程上下文加载器.
- 重载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);
}
}
谢谢!
推荐答案
不要完全跳过超类加载器.尝试这样的事情吗?
Don't skip super class loaders completely. Try something like this?
@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;
}
这篇关于使用自定义ClassLoader覆盖类的现有实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!