Java ClassLoader delegation model?
When calling loadClass()
on a ClassLoader
, does the ClassLoader
first check if the class has been loaded, or does it immediately delegate this check to its parent ClassLoader
?
Java API says:
When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or re开发者_开发问答source itself.
But there's a specific chapter about class loader in the book Java Reflection in Action that says:
Class loader calls findLoadedClass to check if the class has been loaded already. If a class loader does not find a loaded class, calls loadClass on the parent class loader.
Which is correct?
A proper class loader implementation will:
- Check if the class has already been loaded.
- Typically ask the parent class loader to load the class
- Attempt to find the class in its own class path.
The default implementation of ClassLoader.loadClass is something like:
protected synchronized Class<?> loadClass(String name, boolean resolve) {
// First, check if this class loader has directly defined the class or if the
// JVM has initiated the class load with this class loader.
Class<?> result = findLoadedClass(name);
if (result == null) {
try {
// Next, delegate to the parent.
result = getParent().loadClass(name);
} catch (ClassNotFoundException ex) {
// Finally, search locally if the parent could not find the class.
result = findClass(ex);
}
}
// As a remnant of J2SE 1.0.2, link the class if a subclass of the class
// loader class requested it (the JVM never calls the method,
// loadClass(String) passes false, and the protected access modifier prevents
// callers from passing true).
if (resolve) {
resolveClass(result);
}
return result;
}
Some class loader implementations will delegation to other non-parent class loaders (OSGi, for example, delegates to a graph of class loaders depending on the package), and some class loader implementations will look for classes in a local classpath before delegating.
The Java API is correct.
When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.
From the Java Classloading Mechanism -
When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.
The two statements are not exactly mutually exclusive. The Class will only exist in the current ClassLoader's set of loaded classes if the parent ClassLoader had previously failed to find the Class. So,
When requested to find (the external data that describes) a class or resource, a ClassLoader instance will delegate the search for (the external data that describes) the class or resource to its parent class loader before attempting to find (the external data that describes) the class or resource itself.
Which does not prevent it from short-circuiting if it knows its parent can't find the class but it can (as shown by it previously loading the class)
This is basically how it works. You type
Foo f = new Foo();
At this point the classloader will determine if Foo()
have been loaded viz its bits in memory/perm gen. If it has been loaded, then use that. Otherwise delegate it to the parent class loader to try to resolve the class. The bits of this class are read from disk then loaded into memory. On the next new Foo()
, the class would now be found in memory/loaded.
To concur with Sri's answer, it will always get delegated to the parent and the api is correct. If you are playing with classloading, this can make things a little tricky to get right, or achieve the effects you are after. I would suggest starting the jvm with a minimal classpath and then loading all classes using your custom classloader, the easiest way to do this is to use a URLClassloader or a composite object wrapping a URLClassloader so you would be able to trace which classes are loaded and when.
Also worth bearing in mind that a class A loaded by classloader C != class A loaded by classloader C if C and D are not part of the same classloader-parent-child hierarchy.
There's one more issue that should be noted in this context. The API doc says:
The methods and constructors of objects created by a class loader may reference other classes. To determine the class(es) referred to, the Java virtual machine invokes the loadClass method of the class loader that originally created the class.
Meaning that networks of referencing classes are loaded by the same class loader.
I think all correct.
the api is specification, it describes the basic idea when a class loader starts loading a class.
the book Java Reflection in Action describes the implementations. Before loading a class that check if the class has been loaded already.
It was mentioned in @Sripathi Krishnan's answer
From Java Classloading Mechanism
The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.
Here are some highlights of the class-loading API:
- Constructors in
java.lang.ClassLoader
and its subclasses allow you to specify a parent when you instantiate a new class loader. If you don't explicitly specify a parent, the virtual machine's system class loader will be assigned as the default parent.- The
loadClass
method inClassLoader
performs these tasks, in order, when called to load a class:
- If a class has already been loaded, it returns it.
- Otherwise, it delegates the search for the new class to the parent class loader.
- If the parent class loader does not find the class,
loadClass
calls the methodfindClass
to find and load the class.- The
findClass
method ofClassLoader
searches for the class in the current class loader if the class wasn't found by the parent class loader. You will probably want to override this method when you instantiate a class loader subclass in your application.- The class
java.net.URLClassLoader
serves as the basic class loader for extensions and other JAR files, overriding thefindClass
method ofjava.lang.ClassLoader
to search one or more specified URLs for classes and resources.
精彩评论