0% found this document useful (0 votes)
2 views22 pages

Java ClassLoader

This document provides an overview of Java ClassLoader, explaining its types, how it works, and the process of creating a custom ClassLoader in Java. It details the hierarchical nature of ClassLoaders, the delegation model, and includes sample code for a custom ClassLoader that loads classes from the file system. Additionally, it discusses the execution steps and potential issues when using custom ClassLoaders, particularly on Mac OS X.

Uploaded by

rocky rocz
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views22 pages

Java ClassLoader

This document provides an overview of Java ClassLoader, explaining its types, how it works, and the process of creating a custom ClassLoader in Java. It details the hierarchical nature of ClassLoaders, the delegation model, and includes sample code for a custom ClassLoader that loads classes from the file system. Additionally, it discusses the execution steps and potential issues when using custom ClassLoaders, particularly on Mac OS X.

Uploaded by

rocky rocz
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Java ClassLoader

This article will provide an overview of Java ClassLoader and then


move forward to create a custom ClassLoader in Java.

What is Java ClassLoader?


We know that Java Program runs on Java Virtual Machine (JVM).
When we compile a Java Class, it transforms it in the form of bytecode
that is platform and machine independent compiled program and store
it as a .class file. After that when we try to use a Class, Java
ClassLoader loads that class into memory.

There are three types of built-in ClassLoader in Java:

1. Bootstrap Class Loader – It loads JDK internal classes,


typically loads [Link] and other core classes for example
[Link].* package classes
2. Extensions Class Loader – It loads classes from the JDK
extensions directory, usually $JAVA_HOME/lib/ext directory.
3. System Class Loader – It loads classes from the current
classpath that can be set while invoking a program using -cp or -
classpath command line options.

Java ClassLoader are hierarchical and whenever a request is raised


to load a class, it delegates it to its parent and in this way uniqueness
is maintained in the runtime environment. If the parent class loader
doesn’t find the class then the class loader itself tries to load the class.

Lets understand this by executing the below java program:

[Link]

package [Link];

public class ClassLoaderTest {

public static void main(String[] args) {

[Link]("class loader for


HashMap: "

+
[Link]());

[Link]("class loader for


DNSNameService: "

+
[Link]
.getClassLoader());

[Link]("class loader for this


class: "

+
[Link]());

[Link]([Link]
assLoader());

Output of the above java classloader example program is:

class loader for HashMap: null

class loader for DNSNameService:


[Link]$ExtClassLoader@7c354093

class loader for this class:


[Link]$AppClassLoader@64cbbe37

[Link]$AppClassLoader@64cbbe37

As you can see that [Link] ClassLoader is coming as null


that reflects Bootstrap ClassLoader whereas DNSNameService
ClassLoader is ExtClassLoader. Since the class itself is in
CLASSPATH, System ClassLoader loads it.

When we are trying to load HashMap, our System ClassLoader


delegates it to the Extension ClassLoader, which in turns delegates it
to Bootstrap ClassLoader that found the class and load it in JVM.

The same process is followed for DNSNameService class but


Bootstrap ClassLoader is not able to locate it since its in
$JAVA_HOME/lib/ext/[Link] and hence gets loaded by Extensions
Class Loader. Note that Blob class is included in the MySql JDBC
Connector jar ([Link]) that I have included
in the build path of the project before executing it and its also getting
loaded by System Class Loader.

One more important point to note is that Classes loaded by a child


class loader have visibility into classes loaded by its parent class
loaders. So classes loaded by System ClassLoader have visibility into
classes loaded by Extensions and Bootstrap ClassLoader.

If there are sibling class loaders then they can’t access classes loaded
by each other.

Why write a Custom ClassLoader in Java?


Java default ClassLoader can load files from local file system that is
good enough for most of the cases. But if you are expecting a class at
the runtime or from FTP server or via third party web service at the
time of loading the class then you have to extend the existing class
loader. For example, AppletViewers load the classes from remote web
server.

How does Java ClassLoader Work?


When JVM requests for a class, it invokes loadClass function of the
ClassLoader by passing the fully classified name of the Class.

loadClass function calls for findLoadedClass() method to check


that the class has been already loaded or not. It’s required to avoid
loading the class multiple times.

If the Class is not already loaded then it will delegate the request to
parent ClassLoader to load the class.

If the parent ClassLoader is not finding the Class then it will invoke
findClass() method to look for the classes in the file system.

Java Custom ClassLoader


We will create our own ClassLoader by extending ClassLoader class
and overriding loadClass(String name) method. If the name will start
from [Link] i.e our sample classes package then we will load
it using our own class loader or else we will invoke the parent
ClassLoader loadClass() method to load the class.

The project structure will be like the below image:


[Link]: This is our custom class loader with below methods.

1. private byte[] loadClassFileData(String name):

This method will read the class file from file system to byte array.

2. private Class getClass(String name)

This method will call the loadClassFileData() function and by


invoking the parent defineClass() method, it will generate the
Class and return it.

3. public Class loadClass(String name):

This method is responsible for loading the Class. If the class


name starts with [Link] (Our sample classes) then it
will load it using getClass() method or else it will invoke the
parent loadClass function to load it.
4. public CCLoader(ClassLoader parent):

This is the constructor which is responsible for setting the parent


ClassLoader.

[Link]

import [Link];

import [Link];

import [Link];

import [Link];

/**

* Our Custom Class Loader to load the classes.


Any class in the [Link]

* package will be loaded using this ClassLoader.


For other classes, it will

* delegate the request to its Parent ClassLoader.

*/

public class CCLoader extends ClassLoader {

/**
* This constructor is used to set the parent
ClassLoader

*/

public CCLoader(ClassLoader parent) {

super(parent);

/**

* Loads the class from the file system. The


class file should be located in

* the file system. The name should be


relative to get the file location

* @param name

* Fully Classified name of class,


for example [Link]

*/

private Class getClass(String name) throws


ClassNotFoundException {

String file = [Link]('.',


[Link]) + ".class";

byte[] b = null;

try {
// This loads the byte code data from
the file

b = loadClassFileData(file);

// defineClass is inherited from the


ClassLoader class

// that converts byte array into a


Class. defineClass is Final

// so we cannot override it

Class c = defineClass(name, b, 0,
[Link]);

resolveClass(c);

return c;

} catch (IOException e) {

[Link]();

return null;

/**

* Every request for a class passes through


this method. If the class is in

* [Link] package, we will use this


classloader or else delegate the
* request to parent classloader.

* @param name

* Full class name

*/

@Override

public Class loadClass(String name) throws


ClassNotFoundException {

[Link]("Loading Class '" +


name + "'");

if ([Link]("[Link]")) {

[Link]("Loading Class
using CCLoader");

return getClass(name);

return [Link](name);

/**

* Reads the file (.class) into a byte array.


The file should be
* accessible as a resource and make sure that
its not in Classpath to avoid

* any confusion.

* @param name

* File name

* @return Byte array read from the file

* @throws IOException

* if any exception comes in


reading the file

*/

private byte[] loadClassFileData(String name)


throws IOException {

InputStream stream =
getClass().getClassLoader().getResourceAsStream(

name);

int size = [Link]();

byte buff[] = new byte[size];

DataInputStream in = new
DataInputStream(stream);

[Link](buff);

[Link]();
return buff;

[Link]:

This is our test class with main function where we are creating object
of our ClassLoader and load sample classes using its loadClass
method. After loading the Class, we are using Java Reflection API to
invoke its methods.

[Link]

import [Link];

public class CCRun {

public static void main(String args[]) throws


Exception {

String progClass = args[0];

String progArgs[] = new String[[Link]


- 1];

[Link](args, 1, progArgs, 0,
[Link]);
CCLoader ccl = new
CCLoader([Link]());

Class clas = [Link](progClass);

Class mainArgType[] = { (new


String[0]).getClass() };

Method main = [Link]("main",


mainArgType);

Object argsArray[] = { progArgs };

[Link](null, argsArray);

// Below method is used to check that the


Foo is getting loaded

// by our custom class loader i.e CCLoader

Method printCL = [Link]("printCL",


null);

[Link](null, new Object[0]);

[Link] and [Link]:

These are our test classes that is getting loaded by our custom
classloader. They also have a printCL() method that is getting invoked
to print the ClassLoader that has loaded the Class. Foo class will be
loaded by our custom class loader which in turn uses Bar class, so
Bar class will also be loaded by our custom class loader.

[Link]

package [Link];

public class Foo {

static public void main(String args[]) throws


Exception {

[Link]("Foo Constructor >>> "


+ args[0] + " " + args[1]);

Bar bar = new Bar(args[0], args[1]);

[Link]();

public static void printCL() {

[Link]("Foo ClassLoader:
"+[Link]());

[Link]

package [Link];
public class Bar {

public Bar(String a, String b) {

[Link]("Bar Constructor >>> "


+ a + " " + b);

public void printCL() {

[Link]("Bar ClassLoader:
"+[Link]());

Java Custom ClassLoader Execution Steps


First of all we will compile all the classes through command line. After
that we will run CCRun class by passing three arguments. The first
argument is the fully classified name for Foo class that will get loaded
by our class loader. Other two arguments are passed along to the Foo
class main function and Bar constructor. The execution steps with
output will be like below.

Pankaj$ javac -cp . com/journaldev/cl/[Link]

Pankaj$ javac -cp . com/journaldev/cl/[Link]


Pankaj$ javac [Link]

Pankaj$ javac [Link]

[Link]: warning: non-varargs call of


varargs method with inexact argument type for last
parameter;

cast to [Link]<?> for a varargs call

cast to [Link]<?>[] for a non-varargs


call and to suppress this warning

Method printCL = [Link]("printCL", null);

1 warning

Pankaj$ java CCRun [Link] 1212 1313

Loading Class '[Link]'

Loading Class using CCLoader

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

Foo Constructor >>> 1212 1313

Loading Class '[Link]'


Loading Class using CCLoader

Bar Constructor >>> 1212 1313

Loading Class '[Link]'

Bar ClassLoader: CCLoader@71f6f0bf

Foo ClassLoader: CCLoader@71f6f0bf

ctk-pcs1313512-2:src pk93229$

If you look into the output carefully, first its trying to load
[Link] class but since its extending [Link]
class, its trying to load it first and the request it coming to CCLoader
loadClass method that is delegating it to the parent class. So the
parent class loaders are loading the Object, String and other java
classes. Our ClassLoader is only loading Foo and Bar class from the
file system that is getting clear when we invoke their printCL()
function.

Note that we can change the loadClassFileData() functionality to read


the byte array from FTP Server or by invoking any third party service
to get the class byte array on the fly.

I hope that the article will be useful in understanding Java


ClassLoader working and how we can extend it to do a lot more that
just taking it from file system.

Updated from comment by m29


We can make our custom class loader as the default one when JVM
starts by using Java Options.
For example, I will run the ClassLoaderTest program once again after
providing java class loader option.
Pankaj$ javac -cp .:../lib/mysql-connector-java-
[Link]
com/journaldev/classloader/[Link]

Pankaj$ java -cp .:../lib/mysql-connector-java-


[Link] -[Link]=CCLoader
[Link]

Loading Class
'[Link]'

Loading Class using CCLoader

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

Loading Class '[Link]'

class loader for HashMap: null

Loading Class
'[Link]'

class loader for DNSNameService:


[Link]$ExtClassLoader@24480457

class loader for this class: CCLoader@38503429

Loading Class '[Link]'


[Link]$AppClassLoader@2f94ca6c

Pankaj$

As you can see that CCLoader is loading the ClassLoaderTest class


because its in [Link] package.

Mac OS X 10.6.4 Issue with ClassLoader


Java Options
If you are working on Mac OS the above execution can throw some
exceptions but it will execute successfully.

Pankaj$$ java -cp .:../lib/mysql-connector-java-


[Link] -[Link]=CCLoader
[Link]

Intentionally suppressing recursive invocation


exception!

[Link]: recursive
invocation

at
[Link](ClassL
[Link])

at
[Link](ClassLo
[Link])

at
[Link]$[Link](ProviderConf
[Link])
at
[Link](Native
Method)

at
[Link](ProviderCo
[Link])

at
[Link](Provid
[Link])

at
[Link](Provider
[Link])

at
[Link](ProviderL
[Link])

at
[Link](GetInstan
[Link])

at
[Link](
[Link])

at
[Link]([Link]
:244)

at
[Link]([Link])

at
[Link]([Link])
at
[Link].PKCS7.<init>([Link])

at
[Link].<init>(Sig
[Link])

at
[Link](JarVerifier
.java:256)

at
[Link]([Link]:
188)

at
[Link](JarFile.j
ava:321)

at
[Link]([Link]:
386)

at
[Link]([Link])

at
[Link]$JarLoader$[Link](URLClassPath
.java:606)

at
[Link](Native
Method)

at
[Link]$[Link](URLClas
[Link])
at
[Link]$JarLoader.<init>(URLClassPat
[Link])

at
[Link]$[Link]([Link])

at
[Link](Native
Method)

at
[Link]([Link]:
320)

at
[Link]([Link]:
297)

at
[Link]([Link]
a:167)

at
[Link]$[Link]([Link]:
192)

You might also like