Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is the Classloader for a class chosen?

Motivation

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.

Question

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?

like image 496
ipavlic Avatar asked Mar 06 '13 14:03

ipavlic


2 Answers

Small intro

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 answer

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

Some extra info

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.

like image 92
pabrantes Avatar answered Sep 29 '22 14:09

pabrantes


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

like image 42
Mikhail Avatar answered Sep 29 '22 16:09

Mikhail