开发者

How to change default class loader in Java?

开发者 https://www.devze.com 2023-03-13 12:54 出处:网络
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:

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 cla开发者_如何学运维sses 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?


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.)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号