0

Can the Java System class Loader really be replaced?

Java has a property named -Djava.system.class.loader for replacing the system class loader.

However, any class created using new, rather than .newInstance() shows AppClassLoader as its class loader.

AppClassLoader is also known as the system class loader, so it doesn't seem that any real replacing is going on.

For example, when running (Oracle Hotspot on Windows JDK 1.8)

// Run with java -Djava.system.class.loader=classLoaders.MyClassLoader Example

public class MyClassLoader extends ClassLoader {
    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    @Override
    public Class loadClass(String name) throws ClassNotFoundException {
        System.out.println("Loading class :" + name);
        return super.loadClass(name);
    }
}

class A {
}

public class Example {
    public static void main(String[] args) throws Exception {
        System.out.println(ClassLoader.getSystemClassLoader());
        System.out.println(new Example().getClass().getClassLoader());
        System.out.println(new A().getClass().getClassLoader());
    }
}

The output is:

Loading class :classLoaders.Example
classLoaders.MyClassLoader@6d06d69c
sun.misc.Launcher$AppClassLoader@58644d46
sun.misc.Launcher$AppClassLoader@58644d46

While the first instance of Example is being loaded by MyClassLoader, and the method getSystemClassLoader returns the MyClassLoader, any class created using new is loaded by the original System Class Loader, so what exactly is being replaced?

Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
Gonen I
  • 5,576
  • 1
  • 29
  • 60
  • 1
    Does this answer your question? [Why is custom system classloader not working?](https://stackoverflow.com/questions/25478223/why-is-custom-system-classloader-not-working) – Jason Law Sep 08 '20 at 07:56

3 Answers3

1

You are just extending ClassLoader and using super.loadClass(); So, some other real class loader is doing the actual class loading.

Behind the scenes, the system seems to be delegating to the System class loader, after you pass on the loading work.

Here the same question is already answered: https://stackoverflow.com/a/25493910/1364747

  1. MyClassLoader is the initiating class loader
  2. AppClassLoader is the defining class loader
  3. All classes loaded in the same package are from defining class loader (which actually loaded the first class in the package).

A class loader L may create C by defining it directly or by delegating to another class loader. If L creates C directly, we say that L defines C or, equivalently, that L is the defining loader of C.

When one class loader delegates to another class loader, the loader that initiates the loading is not necessarily the same loader that completes the loading and defines the class. If L creates C, either by defining it directly or by delegation, we say that L initiates loading of C or, equivalently, that L is an initiating loader of C.

At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader. Each such class or interface belongs to a single run-time package. The run-time package of a class or interface is determined by the package name and defining class loader of the class or interface.

Although MyClassLoader calls super.loadClass, the implementation of ClassLoader->loadClass only finds another instance, and delegates to it.

So, the parent class implementation only passes on the job to a different instance.

Teddy
  • 4,009
  • 2
  • 33
  • 55
  • No, that's not the case. For example defining class A{} and using New never reaches the System.out.println inside MyClassLoader, that's before the delegation – Gonen I Nov 19 '18 at 23:52
  • Class is loaded only once. Already Example has been loaded. So, it won't load again. That could be the reason. You may have to try with another public class in the same package. Then check the result. – Teddy Nov 19 '18 at 23:58
  • Eventually, loading of Example was delegated to AppClassLoader. So, anything "new"ed from inside Example will go only to AppClassLoader. Possibly :) Try loading one class bytes by yourself. And delegating another.. – Teddy Nov 20 '18 at 00:02
  • This is probably why delegation is used instead of inheritance. So that any parent class loader's loadClass can be called from outside. – Teddy Nov 20 '18 at 00:10
-1

You should override your MyClassLoader's toString() method and see if that works.

Perdi Estaquel
  • 819
  • 1
  • 6
  • 21
-2

In the very early boot sequence of the JVM, a class loader must be in place to load the class overriding the class loader. To do this, a number of other classes must also have been loaded, to implement the primordial class loader and build enough of a JVM to properly accept the overridden class loader.

After the class loader has been successfully overridden, it should be calling your override for the rest of the classes.

This means you must take care to not see the early class loader calls to the non-implemented version as errors.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138