Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: The basics of Java class loaders

The basics of Java class loaders

Tutorial Details:

The basics of Java class loaders
The basics of Java class loaders
By: By Chuck McManis
The fundamentals of this key component of the Java architecture
he class loader concept, one of the cornerstones of the Java virtual machine, describes the behavior of converting a named class into the bits responsible for implementing that class. Because class loaders exist, the Java run time does not need to know anything about files and file systems when running Java programs.
What class loaders do
Classes are introduced into the Java environment when they are referenced by name in a class that is already running. There is a bit of magic that goes on to get the first class running (which is why you have to declare the main() method as static, taking a string array as an argument), but once that class is running, future attempts at loading classes are done by the class loader.
At its simplest, a class loader creates a flat name space of class bodies that are referenced by a string name. The method definition is:
Class r = loadClass(String className, boolean resolveIt);
The variable className contains a string that is understood by the class loader and is used to uniquely identify a class implementation. The variable resolveIt is a flag to tell the class loader that classes referenced by this class name should be resolved (that is, any referenced class should be loaded as well).
All Java virtual machines include one class loader that is embedded in the virtual machine. This embedded loader is called the primordial class loader. It is somewhat special because the virtual machine assumes that it has access to a repository of trusted classes which can be run by the VM without verification.
The primordial class loader implements the default implementation of loadClass() . Thus, this code understands that the class name java.lang.Object is stored in a file with the prefix java/lang/Object.class somewhere in the class path. This code also implements both class path searching and looking into zip files for classes. The really cool thing about the way this is designed is that Java can change its class storage model simply by changing the set of functions that implements the class loader.
Digging around in the guts of the Java virtual machine, you will discover that the primordial class loader is implemented primarily in the functions FindClassFromClass and ResolveClass .
So when are classes loaded? There are exactly two cases: when the new bytecode is executed (for example, FooClass f = new FooClass() ;) and when the bytecodes make a static reference to a class (for example, System. out ).
A non-primordial class loader
"So what?" you might ask.
The Java virtual machine has hooks in it to allow a user-defined class loader to be used in place of the primordial one. Furthermore, since the user class loader gets first crack at the class name, the user is able to implement any number of interesting class repositories, not the least of which is HTTP servers -- which got Java off the ground in the first place.
There is a cost, however, because the class loader is so powerful (for example, it can replace java.lang.Object with its own version), Java classes like applets are not allowed to instantiate their own loaders. (This is enforced by the class loader, by the way.) This column will not be useful if you are trying to do this stuff with an applet, only with an application running from the trusted class repository (such as local files).
A user class loader gets the chance to load a class before the primordial class loader does. Because of this, it can load the class implementation data from some alternate source, which is how the AppletClassLoader can load classes using the HTTP protocol.
Building a SimpleClassLoader
A class loader starts by being a subclass of java.lang.ClassLoader . The only abstract method that must be implemented is loadClass() . The flow of loadClass() is as follows:
Verify class name.
Check to see if the class requested has already been loaded.
Check to see if the class is a "system" class.
Attempt to fetch the class from this class loader's repository.
Define the class for the VM.
Resolve the class.
Return the class to the caller.
Some Java code that implements this flow is taken from the file
SimpleClassLoader
and appears as follows with descriptions about what it does interspersed with the code.
public synchronized Class loadClass(String className, boolean resolveIt)
throws ClassNotFoundException {
Class result;
byte classData[];
System.out.println(" >>>>>> Load class : "+className);
/* Check our local cache of classes */
result = (Class)classes.get(className);
if (result != null) {
System.out.println(" >>>>>> returning cached result.");
return result;
}
The code above is the first section of the loadClass method. As you can see, it takes a class name and searches a local hash table that our class loader is maintaining of classes it has already returned. It is important to keep this hash table around since you must return the same class object reference for the same class name every time you are asked for it. Otherwise the system will believe there are two different classes with the same name and will throw a ClassCastException whenever you assign an object reference between them. It's also important to keep a cache because the loadClass() method is called recursively when a class is being resolved, and you will need to return the cached result rather than chase it down for another copy.
/* Check with the primordial class loader */
try {
result = super.findSystemClass(className);
System.out.println(" >>>>>> returning system class (in CLASSPATH).");
return result;
} catch (ClassNotFoundException e) {
System.out.println(" >>>>>> Not a system class.");
}
As you can see in the code above, the next step is to check if the primordial class loader can resolve this class name. This check is essential to both the sanity and security of the system. For example, if you return your own instance of java.lang.Object to the caller, then this object will share no common superclass with any other object! The security of the system can be compromised if your class loader returned its own value of java.lang.SecurityManager , which did not have the same checks as the real one did.
/* Try to load it from our repository */
classData = getClassImplFromDataBase(className);
if (classData == null) {
throw new ClassNotFoundException();
}
After the initial checks, we come to the code above which is where the simple class loader gets an opportunity to load an implementation of this class. As you can see from the source code ,
the SimpleClassLoader has a method getClassImplFromDataBase() which in our simple example merely prefixes the directory "store\" to the class name and appends the extension ".impl" . I chose this technique in the example so that there would be no question of the primordial class loader finding our class. Note that the sun.applet.AppletClassLoader prefixes the codebase URL from the HTML page where an applet lives to the name and then does an HTTP get request to fetch the bytecodes.
/* Define it (parse the class file) */
result = defineClass(classData, 0, classData.length);
If the class implementation was loaded, the penultimate step is to call the defineClass() method from java.lang.ClassLoader , which can be considered the first step of class verification. This method is implemented in the Java virtual machine and is responsible for verifying that the class bytes are a legal Java class file. Internally, the defineClass method fills out a data structure that the JVM uses to hold classes. If the class data is malformed, this call will cause a ClassFormatError to be thrown.
if (resolveIt) {
resolveClass(result);
}
The last class loader-specific requirement is to call resolveClass() if the boolean parameter resolveIt was true. This method does two things: First, it causes any classes that are referenced by this class explicitly to be loaded and a prototype object for this class to be created; then, it invokes the verifier to do dynamic verification of the legitimacy of the bytecodes in this class. If verification fails, this method call will throw a LinkageError , the most common of which is a VerifyError .
Note that for any class you will load, the resolveIt variable will always be true. It is only when the system is recursively calling loadClass() that it may set this variable false because it knows the class it is asking for is already resolved.
classes.put(className, result);
System.out.println(" >>>>>> Returning newly loaded class.");
return result;
}
The final step in the process is to store the class we've loaded and resolved into our hash table so that we can return it again if need be, and then to return the Class reference to the caller.
Of course if it were this simple there wouldn't be much more to talk about. In fact, there are two issues that class loader builders will have to deal with, security and talking to classes loaded by the custom class loader.
Security considerations
Whenever you have an application loading arbitrary classes into the system through your class loader, your application's integrity is at risk. This is due to the power of the class loader. Let's take a moment to look at one of the ways a potential villain could break into your application if you aren't careful.
In our simple class loader, if the primordial class loader couldn't find the class, we loaded it from our private repository. What happens when that repository contains the class java.lang.FooBar ? There is no class named java.lang.FooBar , but we could install one by loading it from the class repository. This class, by virtue of the fact that it would have access to any package-protected variable in the java.lang package, can manipulate some sensitive variables so that later classes could subvert security measures. Therefore, one of the jobs of any class


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
The basics of Java class loaders

View Tutorial:
The basics of Java class loaders

Related Tutorials:

Revolutionary RMI: Dynamic class loading and behavior objects - JavaWorld - December 1998
Revolutionary RMI: Dynamic class loading and behavior objects - JavaWorld - December 1998
 
Java Tip 39: The trick to using a basic Java 1.1 network and file class loader - JavaWorld -
Java Tip 39: The trick to using a basic Java 1.1 network and file class loader - JavaWorld - October 1997
 
Java Tip 70: Create objects from jar files! - JavaWorld - March 1999
Java Tip 70: Create objects from jar files! - JavaWorld - March 1999
 
A ZipClassLoader for automated application distribution - JavaWorld April 2000
A ZipClassLoader for automated application distribution - JavaWorld April 2000
 
Object mobility in the Jini environment - JavaWorld January 2001
Object mobility in the Jini environment - JavaWorld January 2001
 
When is a Singleton not a Singleton? - JavaWorld January 2001
When is a Singleton not a Singleton? - JavaWorld January 2001
 
Master Java with these introductory books - JavaWorld May 2001
Master Java with these introductory books - JavaWorld May 2001
 
The basics of Java class loaders
The basics of Java class loaders
 
Object-oriented language basics, Part 7
Object-oriented language basics, Part 7
 
classworlds
classworlds classworlds is a framework for container developers who require complex manipulation of Java\'s ClassLoaders. Java\'s native ClassLoader mechanims and classes can cause much headache and confusion for certain types of application developers.
 
Good article
Good article
 
Writing Ant Tasks
Writing Ant Tasks A nice feature of Ant is that it is designed to allow you to add your own tasks and use them in an build. This article shows you the basics of writing an Ant task and how to get a task to work.
 
Inside Class Loaders: Debugging
Inside Class Loaders: Debugging This article will show how to solve class-loading problems and to overcome some debugging limitations of the JDK class loaders.
 
JMS Messaging Online Resource
JMS Messaging Online Resource JMS Tutorials JMS provides a way for Java programs to access an enterprise messaging system, also known as message oriented middleware (MOM). Check out the below tutorials.
 
Understanding the Interplay Between Utility Classes and Static Initialization
Java is an OO language, which means much of the functionality of a Java application is encapsulated into cohesive classes that can be instantiated and acted upon.
 
J2EE pathfinder: Implement JSP custom tags in five easy steps
JSP custom tags provide a standardized mechanism for separating presentation and business logic in a dynamic Web page, allowing page designers to focus on presentation while application developers code the back end. In this installment of J2EE pathfinder,
 
Understanding Network Class Loaders Class loaders
One of the cornerstones of Java dynamics, determine when and how classes can be added to a running Java environment.
 
Game Canvas Basics
Introduces the MIDP 2.0 GameCanvas class and the game loop concept. Required reading for all aspiring "first person shooter" developers.
 
Internals of Java Class Loading
When are two classes not the same? When they're loaded by different class loaders. This is just one of many curious side effects of Java's class-loading system. Binildas Christudas shows how different class loaders relate to one another and how (and why)
 
Java Technology Fundamentals
Learn how to use variable arguments lists, the new JConsole utility to monitor applications, and discover ways to learn what you need to know to get Sun certified.
 
Site navigation
 

 

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2006. All rights reserved.