10

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?

ipavlic
  • 4,906
  • 10
  • 40
  • 77

2 Answers2

17

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.

pabrantes
  • 2,161
  • 1
  • 28
  • 34
4

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

Mikhail
  • 4,175
  • 15
  • 31
  • also, a class can be requested in a static initializer – irreputable Mar 06 '13 at 15:11
  • How can any custom classloader be used then? If I start from the some class loaded by `Bootstrap`, then every class would have to use the `Bootstrap` classloader (because it would be called by the class loaded in bootstrap). I would therefore never move to `System` or `Custom`. – ipavlic Mar 06 '13 at 15:14
  • Then somewhere you create your own class loader and instantiate some class through it. And all class instantiated through this class, would have your class loader as current. Which in tern will have a Bootstrap as a parent. – Mikhail Mar 06 '13 at 15:17
  • @Noofiz I feel that mentioning that you can instantiate a classloader and then use it to instantiate other classes would significantly improve the answer. Would you care to edit it to include additional explanations or examples? – ipavlic Mar 06 '13 at 15:23
  • @ipavlic and noofiz: you guys have to be careful though. Because the classloader delegation system specifies that the standard way to load classes is delegate 1st to the classloader's parent and only on fail try to load the class. That means that even though you use the method's class classloader, it still might be it's parent loading the class. (Note: still there are custom class loaders that might use a strategy that they 1st look and only then if not found delegate to their parent) – pabrantes Mar 06 '13 at 15:39
  • Well any way, playing with custom class loader is very dangerous. I think its more theoretical knowledge. If you are breaking conventions and load class yourself ferst, then delegating it to parent, thats for your own risk. This could couse a problem when single class is loaded by different class loaders. And that would be the mess. – Mikhail Mar 06 '13 at 15:44
  • Playing with custom class loaders is only very dangerous if you don't know what you are doing... And what's the problem of a class being loaded by different class loaders? They will be different classes, and there are several uses for that... For example, that's how web containers like Tomcat achieve isolation between webapps. – pabrantes Mar 06 '13 at 15:50
  • The problem is that you can start recieveing ClassCastException, trieing to invoke method with the class loaded from another classloader, as long as thees classes are differernt instances in permanent generation. – Mikhail Mar 06 '13 at 15:53
  • You're focusing in the bad uses of multiple class loaders instead of the good uses of class loaders. Notice that if your application is actually a platform or some sort of container most probably you'll want class isolation and it will be implemented in such way. Tomcat does that, OSGI does that and the list could keep going on... Obviously if you have a single class test application or even a Desktop application that has only a single context then in that scenario I do agree that talking about custom class loaders will probably be a bad idea/over-enginnering.. – pabrantes Mar 06 '13 at 16:06