17

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!

IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756
  • It's in the JRE, of course. Read this, and Google for custom class loader configuration: http://www.javalobby.org/java/forums/t18345.html – duffymo Jul 18 '12 at 15:48
  • @duffymo - please see my comment under Andre's answer - I have the same question for you! – IAmYourFaja Jul 18 '12 at 15:53
  • I don't see the need to ever write a class loader of my own. Not once, in the entire time I've been writing Java. And that's since 1.0 back in 1997. What makes you think you need it? – duffymo Jul 18 '12 at 17:31
  • I have written my own class loader for one use case - we have a reporting application we hand to our employees/subcontractors, so they can report over internet. Obviously we want to be able to update that, and to allow the running application to overwrite its own jar file I hacked a classloader that loads everything on startup. Granted, the requirement could have been solved by several other technologies (WebStart or make it a Webapp etc.), but it fit best with what we already had. That said, writing a classloader that *really* works is hard (access of resources and use of URL's) – Durandal Jul 19 '12 at 12:26

4 Answers4

7

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.

Durandal
  • 19,919
  • 4
  • 36
  • 70
  • This answers the part I wasn't sure about so +1 from me :-) – André Stannek Jul 18 '12 at 16:16
  • +1 worth nothing that "my" ClassLoader is `Thread.currentThread().getContextClassLoader()` i.e. each Thread has a default class loader and they can be different. – Peter Lawrey Jul 18 '12 at 16:44
  • 1
    @Durandal, About Explicit and implicit loading, in the Fizz example, it is sure that custom class loader will not be used.. right? Basically, for Implicit loading, somewhere explicit loading has to initiate the process. Here either he can use Class.forName() for Fizz class to get loaded explicitly or put Fizz class in class path so that JVM will load it. Conclusion is that Custom class loader will work with explicit approach only, for first time. Correct me if i am wrong. – AKS Jun 11 '13 at 17:32
3

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

André Stannek
  • 7,773
  • 31
  • 52
  • Thanks @Andre, but once again, this is an answer to the question "*How do classloaders work?*" I understand the classloader hierarchy - what I don't understand is when and where the JRE default classloader executes the code that creates my `Fizz.class`. – IAmYourFaja Jul 18 '12 at 15:52
  • Try setting a breakpoint in `java.lang.ClassLoader` in the `loadClass()` method. – André Stannek Jul 18 '12 at 15:55
  • I've given it some thought and edited my answer. I'm sorry but I'm not sure on that last part. – André Stannek Jul 18 '12 at 15:59
0

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

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
0

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.

pooh
  • 652
  • 3
  • 2