Assume that we have a class loading hierarchy that looks like this:
Bootstrap
|
System
|
Custom
Let's say that Custom
Classloader is used for loading a class com.example.SomeClass
. It checks if the System
classloader can load it which again checks whether Bootstrap
classloader can load it. Since both can't, com.example.SomeClass
is loaded by Custom
classloader.
Any class that com.example.SomeClass
depends on goes throught the same. I believe I understand that process.
I don't understand why Custom
would try to load com.example.SomeClass
in the first place. How is the current classloader chosen in an Java application?
As you already know, by default Java uses the bootstrap classloader and the system classloader. The first is responsible for loading bootstrap classes (its classpath contains artifacts such as rt.jar) and the second is responsible for holding your application's classpath. Usually the classpath either defined in your environment variable or given at JVM start using the -cp
argument.
The class com.example.SomeClass
will be loaded by your custom classloader Custom
only if one of two things happen: either you define your custom classloader at startup to be used as system classloader or during running time you explicitly load the class through it.
A bit more about each option:
At application start-up: you can define when starting a JVM instance that instead of using Java's default system class loader you want to use your own. To do so, simply call java with the following environment variable defined:
-Djava.system.class.loader=my.tests.classloaders.Custom
In this case what happens is that all classes from your application in that JVM instance will actually be loaded by Custom
class loader.
During runtime: you can at runtime load a class with your custom class loader. This is achieved creating an instance of your custom class loader and loading your class from it
ClassLoader classloader = new CustomClassLoader();
Class someClass = classloader.loadClass("com.example.SomeClass");
Like @Noofiz said in his answer once you have one class loaded all referenced classes that are required and not yet loaded are loaded through the associated class loader. So, if you load one class with your custom class loader all referenced classes will also be loaded through it. When loading all classes you can do whatever you want, log which classes are being loaded, delegate to parent class loader, load the classes by yourself...
Usually the best way to implement a custom class loader is to use the delegation model as you mentioned. This is because a class is actually defined not only by the classes' bytecode but also by its class loader, which means that a class loaded by two different class loaders won't be the same class.
This means that when your custom class loader is delegating to its parent you're making sure that class is available to a wider scope. Most of the time this will be what you want, but not always.
If for some reason you want class isolation then your custom class loader might be implemented the other way around. First it tries to load the class by itself and only if it doesn't find the class (or is a JVM system class or any other classes you might want to skip) delegates it to its parent. For example, web application containers work this way, allowing context redeploy (basically they discard the class loader and create a new one loading everything again) and full class isolation between web apps.
As I already said, handling class loading is not trivial at all and either you really know what you are doing or you'll certainly find yourself in some weird voodoo troubles.
Maybe already way too off topic, but if you wanna get a bit more hands on regarding class loaders and isolation you can check an old open source project called classworlds. Even though this project is old I'm suggesting it because it's a small project, filled with knowledge about class loading mechanisms which you can easily dive into.
Each class is requested in some method for the first time, every method is a part of some class, which was already loaded and has it's classloader defined. So when a new class is required, it's looked up throug curent method's class's classloader. If a class is loaded through custom class loader, it becomes base classloader for all classes loaded by method of such class. JVM specification does not define how to resolve classes statically (load all graph at start up), or dynamicaly (when first time requested). But static loading would take too long so its not used, and we recieve ClassNotFoundError when application is already running. Class and Interface Resolution
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With