How to change default class loader in Java?

人走茶凉 提交于 2019-11-27 01:54:11

问题


Let's say I have three classes, example.ClassA, example.ClassB, and example.ClassLoader. ClassA prints out HelloWorld and ClassB imports example.ClassA and invokes its main() method. If I do this:

java -cp Example.jar -Djava.system.class.loader=example.ClassLoader example.ClassA

It works and uses my class loader. However, if I do this:

java -cp Example.jar -Djava.system.class.loader=example.ClassLoader example.ClassB

ClassB uses my class loader, but ClassA (which was imported by ClassB) is loaded using a default class loader.

Is there any way to force Java to always use my class loader (unless another class loader is specified explicitly)?

EDIT: Thanks to Paŭlo Ebermann's answer below, I figured the problem is that I'm calling the parent class loader (URLClassLoader) to load the classes that I don't need to touch, and those loaded classes set that as it's context class loader, so classes imported from it uses the parent class loader of my custom loader. (confusing, sorry) Now I can get it to work by manually reading in EVERY class, however it seems redundant as I've copied URLClassLoader's code directly. 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?


回答1:


If your class loader is implemented right, it will first ask its parent class loader about any classes that should be loaded.

The parent class loader of your loader will likely be the usual application class loader. This means that every class your class loader loads will first searched on the application class loader, and only if not found, on your one.

All classes which are defined by your class loader will also search their needed classes on your classloader. If they don't do, your ClassA is not really loaded by your loader.

If this does not help, you will need to show some code on how you got to your results.


An idea on what to do:

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, 0, array.length);
            }
            catch(IOException io) {
                throw new ClassNotFoundException(io);
            }
        }
        else {
            return super.findClass(name);
        }
    }
}

To your question:

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?

No. The ClassLoader of a class is always the one whose defineClass method was called to create the class. (The context class loader is something else - it is thread specific, and only used by classes which explicitly want to use it, not by classes resolving their own direct dependencies.)



来源:https://stackoverflow.com/questions/6366288/how-to-change-default-class-loader-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!