IAmYourFaja
IAmYourFaja

Reputation: 56914

When do Java class loaders engage?

There's 10 million articles and docs out there on what Java classloaders are, and how/*why* to write your own...but they all seem to be assuming some things that I can't find a simple answer to!

I understand the job of the classloader: to read bytecode and construct an object from it. Different classloaders do this differently, etc.

But having never had to code against a class loader API in my own code, and never having to write one of my own, I'm having enormous difficulty understanding when a ClassLoader's own code actually fires.

For instance:

public static void main(String[] args) {
    Fizz fizz = new Fizz();
    fuzz.buzz();
}

Here, we have a Fizz object. Before a Fizz can be instantiated, we need a class loader to kick in and load Fizz.class into its cache. Where and when is this happening?!?! It's not explicitly in my code so it must implicitly be somewhere in the JRE...?

Tangential to that question, if I write my own classloader, say, WidgetClassLoader and want to configure it to load either all my application's classes, or perhaps just my Fizz.class, how do I "tie" this WidgetClassLoader into my application so that it knows which classloader to use? Would my code need to explicitly call this classloader or would it be implicit like the first example? Thanks in advance!

Upvotes: 17

Views: 971

Answers (4)

pooh
pooh

Reputation: 662

If you're interested in classloaders and when and how they work, you could also check out the OSGi specification - it seems to me it will be a very interesting read for you. OSGi is a framework for Java which provides modularity, clear code separation and lifecycle management and which is very popular at the moment (e.g. Eclipse itself is based on one).

OSGi uses classloaders heavily and there is a very nice explanation when and how everything with classloading happens inside the spec. Basically they have a separate bundle classloader for each bundle (that's how modules are called) and these classloaders take care of dependencies and fetching the correct class from the other bundle.

Upvotes: 0

Hot Licks
Hot Licks

Reputation: 47729

The actual creation of the class occurs in defineClass. The class is created using a byte array from any of several source.

The normal path to get to defineClass (which is protected) is through findClass (which, of course, is also protected). So the usual entry point is loadClass -> findClass -> defineClass. But there are other paths for special cases.

(The whole thing is quite convoluted, and represents a history of adding layers as protection became more complex and the modes of access more varied.)

Upvotes: 0

Durandal
Durandal

Reputation: 20059

You question isn't as trivial as you think now.

Your Fizz example: When is Fizz loaded? This is defined in the JLS (Chapter 5.4: Linking). It does not define when Fizz is loaded, but it makes guarantees about the visible behavior. For the 'when' part, if Fizz can not be found, an Exception will be thrown from the first statement that accesses Fizz (Fizz fizz = new Fizz()). I'm pretty sure it will be the new Fizz() specifically in this case because the right side of the expression is evaulated first. In case you had written it like this:

Fizz fizz = null;
fizz = new Fizz();

In this case the Fizz fizz = null would already throw the Exception because its the first access to the Fizz class.

Who loads Fizz? When a class must be loaded, the classloader that 'belongs' to the code requiring the class is used to get the class. In the Fizz example this will be the classloader that loaded the class with the main method. Of course, the classloader may choose to delegate to its parent classloader if it can not load Fizz by itself.

How do I get the JVM to use my ClassLoader? There are two ways, explicitly or implicitly. Explicitly: you can load a class through your own classloader by calling its methods. Implcitly: when you execute code (meaning methods or initializers) from a class that was already loaded from your classloader and a class reference needs to be resolved in the process, your classloader will be automatically used because it is the classloader that loaded the code in the first place.

Upvotes: 7

André Stannek
André Stannek

Reputation: 7863

Java has a default class loader. This looks for class declarations in the default class path. If you write your own class loader you can (and should) set the parent class loader. This would be the default if you have no other one. If yuo don't do it your class loader would not be able to find java API classes. If java looks for a class it doesn't start looking with you custom class loader but with the parent class loader. If this one has a parent it starts there and so on. Only if a class could not be found the next child class loader is used to try it again. Again this continues as long as there are children. If the class is not found by any of the loaders in the chain, a ClassNotFoundException is thrown.

Of course java only uses your class loader if you set it as default class loader first (by calling Thread.currentThread().setContextClassLoader()) or load the class manually (by calling loadClass()).

I'm not sure when the class loader is invoked. I think it is invoked either on starting the programm (on all classes declared as import) or on first use of a class (variable declaration or constructor call).

Upvotes: 3

Related Questions