In this article we will understand the basics of Classloader in Java. Let us first understand what is the meaning of classloader.
What is the ClassLoader ?
As its name implies, ClassLoader is a class that loads other classes. More scientific: The Classloader loads the bytecodes in its class to memory, so it can be used throughout your application. The ClassLoader is in the java.lang.ClassLoader package. Understanding the classloader is important for working on the server development or any product developments which is more often design the custom classloaders to load the classes.
You would have come across the ClassNotFoundExecption many times while you are writing Java programming. Classloader is the culprit which causes this exception.
Why do we need the ClassLoader ?
The class loading mechanism allows us to have multiple classes with the same name (exactly the same) but different class loaders. This is what happens for example in web containers today, where we have several different applications but it can happen that one or two classes have the same name, this will not cause any conflict.
Let’s dive deeper into this concept. As we said earlier, everything in Java is loaded by class loaders specific (which will be explained later). So you may ask: If everything is loaded by a ClassLoader and ClassLoader itself is a class that must also be loaded, then who carries the first ClassLoader to load other classes? to solve this problem the “Bootstrap ClassLoader” which is written in native language, is loaded by JVM. It is responsible for initializing the packages essential to run the language pack as the “rt.jar”. Bootstarap classloader is a native implementation. So, it could be different for each JVM implementation.
So if the java classes are loaded dynamically (through the ClassLoader) can I replace the code of a class and load it at runtime? Yes you can. You can still load remote class through any URL at runtime.
Exemplifying the Java ClassLoader
Before jumping into the workings of each ClassLoader in native Java, we have to understand why its use has become so necessary.
The ClassLoader by default loads all classes that are present in your CLASSPATH, so in this case you do not even know the existence of this loading mechanism. Classes are identified by its fully qualified name + class loader that loaded it, so we are sure of a one Class Employee Application 001 is different from the class Employee Application 002.
The use of class loaders is useful, for instance, when working with various versions of applications with different libraries. Ex: Suppose, the application 001 can work with version 3.6 of Hibernate while the application 002 works with the version 3.3. If they were working in the same class loader then there would have been conflicts in classes as org.hibernate.Session will be loaded twice in memory.
Listing 1 : Class Loading
R = Class loadClass (String className, boolean resolveIt);
In the above code, the parameter className is the absolute name of the class, ie, the full name of the package path (net.javabeat.MyClass). The boolean parameter resolveIt says the classes associated with our loaded class, should also be loaded as if it were a cascade of loadings.
ClassLoader Engine
We have 3 types of ClassLoaders, they are:
- Bootstrap ClassLoader
- ClassLoader Extension
- Application ClassLoader
Each of these have their respective function which will be explained in the following sections.
Bootstrap ClassLoader : This is responsible for loading classes from rt.jar and has no parent, this is the father of all others. Therefore, ensure that nobody will modify the rt.jar classes. For example: the package java.lang.
Extension ClassLoader : This is responsible for loading JARs that are within the property java.ext.dirs directory, by default this directory is: $ JAVA_HOME / lib / ext. Bootstrap ClassLoader is the parent classloader for this.
Application ClassLoader : This, is no less important and is responsible for loading all classes in your application, ie, sets your CLASSPATH. Extension ClassLoader is the parent classloader. For a complete example of loading a class dynamically through loadClass, see the listing below.
Listing 2 : Loading Class
public class Main extends ClassLoader { public static void main (String [] args) { ClassLoader classloader = Principal.class.getClassLoader (); try { Class aClass = classLoader.loadClass ("AnotherClass"); System.out.println ("aClass.getName () =" + aClass.getName ()); } Catch (ClassNotFoundException e) { e.printStackTrace (); } } }
The output of the above code will be something like: “aClass.getName () = AnotherClass”.
Well, let’s now create our own ClassLoader, whose main method the “loadClass” which is responsible for loading the class we want.
Listing 3 : Creating our own ClassLoader
</span> <pre>package net.javabeat; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; public class MyClassLoader extends ClassLoader { public MyClassLoader(ClassLoader parent) { super(parent); } public Class loadClass(String name) throws ClassNotFoundException { if ("reflection.MyObject".equals(name)) return super.loadClass(name); try { String url = "" + "Classes / reflection / MyObject.class"; URL myUrl = new URL(url); URLConnection connection = myUrl.openConnection(); InputStream input = connection.getInputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int data = input.read(); while (data != -1) { buffer.write(data); data = input.read(); } input.close(); byte[] classData = buffer.toByteArray(); return defineClass("reflection.MyObject", classData, 0, classData.length); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } }
We see the following in the above code:
- The class is loaded using reflection inside the package and have the name MyObject.
- Use a URL to load this class, otherwise pass the responsibility to the parent ClassLoader.
Let’s now create a main method that uses our ClassLoader.
Listing 4 : Using our ClassLoader
package net.javabeat; public class Main extends ClassLoader { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader(); MyClassLoader classLoader = new MyClassLoader(parentClassLoader); Class myObjectClass = classLoader.loadClass("reflection.MyObject"); AnInterface2 object1 = (AnInterface2) myObjectClass.newInstance(); MyObjectSuperClass object2 = (MyObjectSuperClass) myObjectClass .newInstance(); // Create new class loader so that the classes can be reloaded. classLoader = new MyClassLoader(parentClassLoader); myObjectClass = classLoader.loadClass("reflection.MyObject"); object1 = (AnInterface2) myObjectClass.newInstance(); object2 = (MyObjectSuperClass) myObjectClass.newInstance(); } }
Let us understand the workings of the code above:
- First grab the ClassLoader ie the ClassLoader parent of our (MyClassLoader).
- Then we create an instance of our ClassLoader parent passing it as a parameter, so it can function loadClass delegate to the parent if needed.
- Load the class reflection.MyObject in our new ClassLoader (remember this time it will load a specific URL that is different from our CLASSPATH)
- We now have a class loaded into a classloader of our own, we can now re-run the same class, using a ‘loadClass “.
Summary
Creating your own ClassLoader is a very rare scenario, in fact you may never need to work with it directly. But understanding its usefulness as a whole is essential and knowledge of this is a difference for sure. You can solve problems like NoClassDefFoundError in a short time, just knowing the basic principle of how the ClassLoader works for example in scenarios where a class can exist physically, but in another ClassLoader that is not your application.
This article aims at helping you understand the classloader concepts even though you may not necessarily write your own classloader anytime.
Reference Books:
- Java: The Complete Reference
- Head First Java by Kathy Sierra, Bert Bates