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