Basics of Java Class Loader


Java class loader is an interesting concept of Java Runtime. We know that in Java,  every executable code is stored  in .java files which are compiled to .class files. These class files are stored in file system  in plain directory structure or in jar files or probably using some other medium. When any java program runs, it needs the definition of referred class files to execute this code at runtime. Here comes the role of Java Class Loader. Whenever Java runtime needs any class file, it calls a component of Java runtime called class loader to load the desired class. Default class loaders of Java i.e. Bootstrap and System Class Loader has the logic to search for the class file in JVM and in  directories and jars included in classpath respectively. It assumes that if Java program is referring to java.lang.Object, then the definition of this class must  be somewhere on  classpath in  java/lang/Object.class hierarchy. So by default, it has the logic to search in directories and jars. Once it finds the class file, it loads it in memory, store it with in memory cache for future reference and return to the runtime. So class loader search for the class files only once, and stores it in memory data structure to be utilized on future calls. Java classes loaded from default class loader are considered as trusted classes and hence these have the access to all core classes of java library itself.

Now Java provide enough flexibility to users applications to define their own custom class loaders, which can extend the default class loaders, and can add custom logic; like to load the classes from a  network location or from database and so on. Working of class loaders generally used to be like; a custom class loader first ask the parent default class loader of Java runtime to load the requested class. If default class loader is unable to find the class, then extended class loader proceed to load that class using its specific loading algorithm.
Here is a catch. As there are many package private properties and methods available in Java default libraries. So if custom class loader allow to load a class like java.lang.Object, this class will be having the access to all package private properties of this package. This way, any untrusted class can have access to library methods and hence can change the behavior of application. Similarly if a malicious Java Security Manager class (java.lang.SecurityManager) is being loaded by custom class loader, it can take over the security of whole system. To avoid such scenarios, custom class loaders must put a check that it won't try to load the System default files using its own logic and will always give the first chance to default loader to load the class. That way,  we close the gap  using which any untrusted class can be loaded in JVM in system  packages.

When you implement a custom class loader,  there used to  be few steps which needs to be followed. These are:

  • Check  the class  name and put any validation if required
  • Check if class is already loaded, if yes return the same
  • Give the parent class  loader (default) a chance to load the class, if found return it
  • Check if class is system class, if yes throw the error as custom class loader should not load system class from custom location
  • Load the class from custom location
  • Define the class using parent's method
  • Resolve the class using parent's method
  • Store the class in local cache
  • Return the class
Define class method is an important step using which Java runtime verify the class file. Also it internally load the class in internal data structure.  Resolve class method check  the class file for further references  and ensure to load all referenced classes.

One important point to consider is, identity of any class. Any class is usually identified by its fully qualified class name. However, at system level, a class is identified by its fully qualified name + its class loader. That means, if same class is loaded from two different class loaders in same JVM, these will not be same. This situation occurs mainly in distributed systems when one class is loaded by two different class loaders. In that case, you will not be able to assign the objects to reference of each other. It will result into ClassCastException.

Also we need to understand the special case of 'NoClassDefFoundError'. Do remember, when system is loading the class, it tries to resolve the class using 'resolveClass' method of class loader. Resolve method tries to locate all referenced classes of main class (generally). At this time, if any of the referenced class is not found, system will throw the 'NoClassDefFoundError'. So we need to understand that 'NoClassDefFoundError' can be thrown not only for main class which is loading right now, but it can also be thrown for referenced classes from it.

These are the basics of Java class loaders. Further we shall discuss about Class Loader sandboxing in coming blogs. Till then, try to make simple class loaders which can load the class from a specific folder which is not on class path, or from a network location. Discussions are welcome. 

People who read this post also read :



2 comments:

Anonymous said...

When I open this page, It always a block bar is appear in the center of this site and it hides several important points.
Could u solve this problem?

Mohit Gupta said...

Problem has been solved!!

Post a Comment