java -cp Example.jar -Djava.system.class.loader=example.ClassLoader example.ClassA
它工作并使用我的类加载器.但是,如果我这样做:
java -cp Example.jar -Djava.system.class.loader=example.ClassLoader example.ClassB
ClassB使用我的类加载器,但ClassA(由ClassB导入)使用默认的类加载器加载.
有没有办法强制Java总是使用我的类加载器(除非另有一个类加载器被明确指定)?
编辑:感谢下面的PaŭloEbermann的回答,我发现问题是我调用父类加载器(URLClassLoader)加载我不需要触摸的类,而那些加载的类设置为上下文类加载器,所以从其导入的类使用我的自定义加载器的父类加载器. (令人困惑,抱歉)现在我可以通过手动阅读每个类来使其工作,但是看起来很多,因为我直接复制了URLClassLoader的代码.有没有办法告诉父类装载器来查找和定义类,但是将Class的上下文类加载器设置为您的自定义类加载器?
解决方法
您的加载器的父类加载器可能是通常的应用程序类加载器.这意味着您的类加载器加载的每个类将首先在应用程序类加载器上搜索,并且只有在您找不到的时候才会搜索.
您的类加载器定义的所有类也将在类加载器上搜索所需的类.如果他们不这样做,你的ClassA并不是由你的装载机加载的.
关于做什么的想法:
class ModifyingClassLoader extends URLClassLoader { // TODO: add constructors private boolean needsModifying(String name) { // TODO } private byte[] modifyClass(InputStream original) throws IOException { // TODO } public Class<?> findClass(String name) throws { if(needsModifying(name)) { try { InputStream classData = getResourceAsStream(name.replace('.','/') + ".class"); if(classData == null) { throw new ClassNotFoundException("class " + name + " is not findable"); } byte[] array = modifyClass(classData); return defineClass(name,array,array.length); } catch(IOException io) { throw new ClassNotFoundException(io); } } else { return super.findClass(name); } } }
对你的问题:
Is there a way to tell the parent class loader to find and define the class,
BUT set the Class’s context class loader to your custom one?
不,类的ClassLoader总是一个被调用来创建类的defineClass方法的类. (context class loader是别的 – 它是线程特定的,只有明确想要使用它的类才使用,而不是通过解析自己的直接依赖关系的类来使用).