Class ClassLoader in Java

Class ClassLoader in Java

ClassLoader is an abstract class. The applications implement subclasses of Classloader to extend the mechanism by which JVM dynamically loads classes.

The class loader loads the class files from the code and Java API’s library. (The necessary class files those are needed to execute the program are loaded.) Then the whole set of byte codes are executed into an execution engine.

The execution engine is one of the integral parts of the virtual machine which has several implementations. The simple and straightforward implementation sequentially interprets the byte codes.

The complex one is the just in time compiler. In this implementation byte codes of a method are compiled to native machine code has the first occurrence of the method invocation. The native machine code, then cached for reusability.

The third type of implementation is called Adaptive Optimizer. In this implementation, the virtual machine starts interpreting byte codes, but actively monitor the activities. The monitor process keeps noting down the heavily used area of the code. As an optimization process, the virtual machine compiles to native machine code and keep optimizing the heavily used area of the code.

The remaining area of the code .which is used but not that heavily remains as byte codes, which the virtual machine keeps on interpreting. Majorly it uses a Pareto principle (80-20 rule) to identify the heavily need an area of the code. This 20 % of the code falls under performance improvement.

Finally, the JVM built on top of a chip that executes the java byte codes natively. The execution engine is embedded in the chip. When the JVM runs on top of an operating system, a Java program talks to the operating system by invoking native methods.

In Java there are two types of methods:-

  • Java’s internal methods
  • Native methods.

Java’s internal methods are written in the Java language. They are compiled to byte codes. They are saved in separate class files. A native method is written on some other languages(C, C++ etc.)

They are compiled to the native machine codes for a specific processor. Native Methods are stored in DLL (dynamic link library files). While the java methods are platform dependant native Methods are platform-specific.

When running a  java program, it intern calls the native methods. The virtual machine then loads the corresponding DLL file that contains the specific and corresponding method. Once involved, Java executes the method.

Native Methods can provide Java direct access to the resources of the beneath operating system. Now Native methods will render our code to a controlled platform-specific environment as they are all platform dependant. They may also render our code to a particular implementation of the  Java platform.

The Java Native Interface(JNI) enables native methods to execute on a computer for any Java platform. There may be chances where we want to access resources of any particular host and that may be unavailable. In that case, we need to write our API’s to call native Methods to make our code system independent.

The ClassLoader Architecture

The class loader architecture acts as a safeguard for Java’s security and helps in network mobility. Inside the Java virtual machine, there can be more than one class loader. The JVM (Java Virtual Machine) has a set of flexible and custom class loaders that allows classes to load in customized ways.

A Typical Java application can utilize two different types of class loaders.

They are as follows-

  • Bootstrap class loader
  • User-defined class loader.

Bootstrap ClassLoader

The bootstrap class loader is a part of the Java Virtual Machine implementation. It is often referred to as primordial class loader or the system class loader or default class loader.  For example, if a Java Virtual Machine is Implemented as a c++ program on top of an existing operating system, the bootstrap Classloader will be part of the c++ coding. The Bootstrap class loader loads classes from Java API’s and local drives.

During execution, a Java application can install user-defined class loaders which load classes in the different customized way ( like download a class from network and load). Extract from the database, or build them on the fly.

User-Defined ClassLoader

User-defined class loaders are not an intrinsic part of the Java Virtual Machine. The user-defined class loaders are always a virtual machine. They are instantiated like normal class viz objects.

Because of the user-defined class loaders, we do not need to know all the classes that may ultimately help in running our application during compile time. They enable us to dynamically extend a Java application at runtime. During execution, Java can figure out the extra classes that need to be loaded .

Once Java figures out the list of classes, Java Virtual Machine, with the help of user-defined class loaders, load them one by one.

A part of JVM implementation
A part of JVM implementation

During the class loading process Java, Virtual Machine keeps track of the class loader. ( User-defined or bootstrap ) and the class loader. If a loaded class refers to another class, the virtual machine checks the class loader from its track record and request’s the same class loader to load the referenced class.

Example, if the user defined loader loads a class ‘shape’ and that shape class now has a reference to’ Triangle’ class, The JVM ( Java Virtual Machine) will request the same user-defined class loader to load Triangle class. This phenomenon enables us to create multiple name-spaces inside a single Java application.

Now a Java application can instantiate multiple user-defined class loaders. They can reside in the same class or different classes. Hence the application may create multiple numbers of class loaders.

Interestingly classes loaded by different class loaders are in different namespaces. They cannot access others until and unless the application explicitly permits this access operation. So when we write our Java application code, we can very well segregate classes loaded from different sources into different namespaces.

The class loader architecture helps to control the interaction between code loaded from different sources. This also prevents any hostile code from gaining access to any of the resources.

By enabling us to instantiate user-defined class loaders that know how to download class files from networks, Java’s class loader architecture thus support network mobility. Java also supports security by enabling us to load class files from different sources through different user-defined class loaders. Lastly, the class files from sources are put in the different namespace that restricts access between codes.

ClassLoader Working Principle

In general JVM loads classes from the local file system in a platform-dependent manner(directory defined by CLASSPATH), however, some classes may be originated from another source like network or by an application.

The ClassLoader class provides a mechanism for Java to load classes over a network or from any source other than the local filesystem. The default class-loading mechanism loads classes from files found relative to directories specified by the CLASSPATH environment variable. This default mechanism does not use an instance of the ClassLoader class.

See also  Class CollectionElementIterator in Java
Three pillars of Java
Three pillars of Java

An application can implement another mechanism for loading classes by declaring a subclass of the abstract ClassLoader class. A subclass of ClassLoader must override the loadClass() to define a class-loading policy.

This method implements any sort of security that is necessary for the class-loading mechanism. The other methods of ClassLoader are final, so they cannot be overridden.

A ClassLoader object is typically used by calling its loadClass() method to explicitly load a top-level class, such as a subclass of Applet. The ClassLoader that loads the class becomes associated with the class; it can be obtained by calling the getClassLoader() method of the Class object that represents the class.

VirtualMachine primary task
VirtualMachine primary task

Once a class is loaded, it must be resolved before it can be used. Resolving a class means ensuring that all of the other classes it references are loaded. Besides, all of the classes that they reference must be loaded, and so on, until all of the needed classes have been loaded. Classes are resolved using the resolveClass() method of the ClassLoader object that
loaded the initial class. This means that when a ClassLoader object is explicitly used to load a class, the same ClassLoader is used to load all of the classes that it references, directly or indirectly.

Classes loaded using a ClassLoader object may attempt to load additional classes without explicitly using a ClassLoader object. They can do this by calling the Class class’ forName() method. However, in such a situation, a ClassLoader object is implicitly used. See the description of Class.forName() for more information.

How Virtual machine works
How Virtual machine works

Java identifies a class by a combination of its fully qualified name and the class loader that was used to load the class. If you write a subclass of ClassLoader, it should not attempt to directly load local classes. Instead, it should call findSystemClass().

A local class that is loaded directly by a ClassLoader is considered to be a different class than the same class loaded by findSystemClass(). This can lead to having two copies of the same class loaded, which can cause several inconsistencies. For example, the class’ equals() method may decide that the same object is not equal to itself.

In short, this class defines the necessary hook for Java to load classes over the network, or from other sources. Normal applications do not need to use or subclass this class.

The method defineClass() converts an array of bytes into an instance of a class. Instances of this newly created /defined class can be created by using the newInstance() method of the class-Class. The methods and constructors of objects created by a ClassLoader may reference other classes.

To determine the class(es) referred to, the JVM calls the loadClass() method of the ClassLoader that created the class. If JVM only needs to determine if the class exists or if it does not exists, to know its superclass, the resolve flag is set to false. However if an instance of the class is being created or any of its methods are being called, the class must also be resolved.

In this case, the flag resolve is set to true and the resolveClass() method is called.

The class loader Architecture

As the class loader’s main objective is to bring any code to Java Virtual Machine, the class loader’s architecture provides the basic security for the customer who uses Java.

The class loader architecture provides security for sandbox in three different ways –

  1. Preventing malicious code from interfering the actual code. It provides separate namespaces for classes loaded by different class loaders. (Namespace is a set of unique names provided one name by each class loader (Java Virtual Machine maintains for further use).
  2. Acting as a guard for trusted class libraries.
  3. Segregating code into categories (putting all code into protection domains) to that Java Virtual Machine can determine which actions the code can operate.

These segregations of Namespaces enclose the classes with a guarding technique. Now inside Java Virtual Machine same namespace’s classes can interact with each other, but an explicit mechanism to unhide them is required.

(The other namespaces remain undetected otherwise).

class loader and namespace
class loader and namespace

Two class loaders, class loader 1 and class loader 2 are trying to load types. Both have a common type called Pig type to load. Once they load the type data’s, the Pig type is loaded twice. Now if Goat is trying to refer Pig, the reference gets created in the namespace 1’s Pig, similarly if Hen is trying to create a reference to Pig, that gets created in the namespace 2’s Pig.

Now as per JVM architecture, they (Goat and Hen) do not know the existence of Pig in other namespaces.

So, in general, they cannot interfere with each other.

However, we can provide them (types that belong to the same package) members protected or package level access to access other namespaces type. This is applicable when they are loaded by the same class loader.

A user-defined class loader depends on Java virtual machine’s core class loader to load a class. This event is fulfilled by calling load class () method.

The other way a class loader (user-defined) may load a class by bootstrap class loader using find system class () method. The process by which one class loader requests another class loader to load a class is known as a parent-delegation process. (Except Bootstrap loader)

Each class loader class has a parent that can load a class. So, when a class loader receives a request to load a class, it invokes its parent class loader and delegates the loading task. The invocation of parent and delegation of loading task keep on propagating to Bootstrap class to load. Bootstrap is the last and final class loader in the chain.

If a parent class loader is able to load a class it returns the reference to the child class loader and it propagates till the last class loader in the chain. In case, parent class loader cannot load the class, the lowermost class loader itself tries to load the class.

The built-in class loaders are called Primordial class loader previously which is now renamed as Bootstrap class loader now.

The responsibility of a Bootstrap class loader is to load only class files of the Core Java APIs. The Bootstrap idea is originated from the concept that the class files of the core Java API are essential to “Bootstrap” the Java Virtual Machine.

class loader hierarchy
classloader hierarchy

The activities to load other class files are as follows –

  1. Identify the class files for the application that is being executed.
  2. Identify the class files that are installed.
  3. Identify the class files that are being downloaded.
  4. Discover the files from the classpath and so on.

Initially, when Java Virtual Machine starts its operation, it creates at least one user-defined class loader (may create many also!) first. All the class loaders used to be in a parent-child relationship (where the top of the chain used to be bootstrap class loader. The starting of the chain is system class loader (built-in class loader)

The issue with this architecture if we need to load a class that is not a part of these class loader or a part of an installed extension or on the classpath, the class loader will not load the class. So when these class loader cannot load the class, our custom class loader will try to load it in a customized way (maybe downloading it from the network).

See also  Learn Abstract Class in Java in a Simple and Fast Manner

Secondly, if the class tries to access (upon invocation) any class from Java API (say Java.util. For matter), as it the first time the class loader (the custom one that loaded this class) finally reaches out to Bootstrap class loader for help. The classpath class loader does not look for the type on the classpath. The custom class loader does not download it from the network. Because the Bootstrap class loader finds the class, the installed extension class loader does not attempt to find it.

This is how the class loader architecture stands as a guard against malicious code that may trick the Java Virtual machine by fooling, it was a trusted class from the Java API. Otherwise, it may penetrate to Java’s security model and break the sandbox. The class loader architecture thus prevents malicious code (untrusted classes) from impersonating as a trusted class.

As the parent-delegation method delegates the class loading activity finally to Bootstrap class loader, it can check the most trusted library – the Core Java API (that is checked first for each type). The second priority is given to the standard extensions which are checked then. Third, the local class files fetched from the local classpath are verified. Finally, the network class loader that downloads class (s) from the network is checked and verified.

In the checking process, if some Code coming from the network has the same name as one of the Core Java API like Java.lang.Float, the loading action is terminated. Instead, the class returned by the parent’s Core Java API (coming from Bootstrap loader) will be repurposed and used.

The second scenario can be – (the code coming from the network does not have the same name as in Core Java API, instead it is a brand-new code and trying to replace a trusted type. In that case, also, the request to load the new class reaches up to Bootstrap loader. As the new type cannot be found in Core Java API classes, or on the classpath, it will finally try to load the new class using network class loader.

Now, as per rule, and architecture, the Core Java API classes are loaded by Bootstrap loader and the new class is loaded by network class loader. In this situation, they don’t get mixed. They will be placed in two different runtime environments.

The runtime environment or runtime packages mean to be a set of types that belong to the same package and are all loaded by the same class loader.

Now before enabling access to package visible members (members with protected or package level access between two types the Java Virtual machine confirms that these two types are coming from the same package. It also checks and confirms that they reside to same runtime environment or runtime package.

This implicitly means that these classes are loaded by the same class loader.

This is how the Java network loader when loads a class/type from the network can be safe to work.

The Bootstrap class loader loads the Core Java APIs (most trusted). An installed extensions class loader loads class files from any installed extensions are loaded with different class loaders they cannot gain access to package visible members of the installed extensions or Core Java APIs.

Java class loaders do not load a class for certain forbidden types. A class loader has a set of class names and package name that are forbidden in nature. If the class loader finds a match with the list, the class loader immediately throws a security exception.

Class loaders generally put each loaded class into a protecting domain. The protecting domain defines what permissions are granted to these classes.

So, if a class is being created and set to be loaded by classpath class loader and the class is put in the local classpath so that the classpath class loader can access it, in that case, the package of the class comes into consideration. In case, if the classes loaded by class loader are set in such way that the classes of the package are not accused by the class loader, in that case, class loader checks if the requested class is not part of the package.

In case, if the class name matches, the class loader does not pro gate the name of the class to its parent class loader. It simply throws a security exception.

The structure of the ClassLoader class is given below:

public abstract class java.lang.ClassLoader extends java.lang.Object{
//constructor
protected ClassLoader();//creates a new classloader and initializes it. if there is a security manager, it check by createClassLoader() method.It may result in a SecuryException if the current thread does not have permission to create a new ClassLoader.
//Methods:
// Protected Constructor
protected ClassLoader();
// Class Methods
public static final URL getSystemResource(String name);
public static final InputStream getSystemResourceAsStream(String name);
// Public Instance Methods
public URL getResource(String name);
public InputStream getResourceAsStream(String name);
public Class loadClass(String name) throws ClassNotFoundException;
// Protected Instance Methods
protected final Class defineClass(byte[] data, int offset, int length);
protected final Class defineClass(String name, byte[] data, int offset,int length);
protected final Class findLoadedClass(String name);
protected final Class findSystemClass(String name) throws ClassNotFoundException;
protected abstract Class loadClass(String name, boolean resolve) throws ClassNotFoundException;
protected final void resolveClass(Class c);
protected final void setSigners(Class cl, Object[] signers);
} 

The details of the class structure are given as follows:

protected ClassLoader();

protected ClassLoader() constructor initializes a ClassLoader object. Because ClassLoader is an abstract class, only subclasses of the class can access this constructor.

public static final URL getSystemResource(String name);

public static final URL getSystemResource(String name) method finds a system resource with the given name and returns a URL object that is connected to the resource. The resource name can be any system resource.

This method returns a URL object that is connected to the specified system resource or null if the resource cannot be found.

Parameter
name – A system resource name.

public static final InputStream getSystemResourceAsStream(String name);

public static final InputStream getSystemResourceAsStream(String name) method finds a system resource with the given name and returns an InputStream object that is connected to the resource. The resource name can be any system resource.

This method returns an InputStream object that is connected to the specified system resource or null if the resource cannot be found.

Parameter
name – A system resource name.

public URL getResource(String name);

public URL getResource(String name) method finds a resource with the given name and returns a URL object that is connected to the resource.

A resource is a file that contains data (e.g., sound, images, text) and it can be part of a package. The name of a resource is a sequence of identifiers separated by “/”. For example, a resource might have the name test/mypackage/applogon.html.

System resources are found on the host machine using the conventions of the host implementation. For example, the “/” in the resource name may be treated as a path separator, with the entire resource name treated as a relative path to be found under a directory in CLASSPATH.

See also  Array Concept Simplified in Java

The implementation of getResource() in ClassLoader simply returns null. A subclass can override this method to provide more useful functionality.

This method returns a URL object that is connected to the specified resource or null if the resource cannot be found.
Parameter
name – A system resource name.

public InputStream getResourceAsStream(String name);

public InputStream getResourceAsStream(String name) method finds a resource with the given name and returns an InputStream object that is connected to the resource.

A resource is a file that contains data (e.g., sound, images, text) and it can be part of a package. The name of a resource is a sequence of identifiers separated by ‘/’. For example, a resource might have the name test/mypackage/applogon.html.

System resources are found on the host machine using the conventions of the host implementation. For example, the ‘/’ in the resource name may be treated as a path separator, with the entire resource name treated as a relative path to be found under a directory in CLASSPATH.

The implementation of getResourceAsStream() in ClassLoader simply returns null. A subclass can override this method to provide more useful functionality.

This method returns an InputStream object that is connected to the specified resource or null if the resource cannot be found.
Parameter
name – A system resource name.

public Class loadClass(String name);

public Class loadClass(String name) method loads the named class by calling loadClass(name, true).

This method returns the Class object for the specified class.
Parameter
name – The name of the class to be returned. The class name should be qualified by its package name. The lack of an explicit package name specifies that the class is part of the default package.

protected final Class defineClass(byte[] data, int offset, int length);

protected final Class defineClass(byte[] data, int offset, int length) method creates a Class object from the byte codes that define the class. Before the class can be used, it must be resolved. The method is intended to be called from an implementation of the loadClass() method.
Note that this method is deprecated as of Java 1.1. We need to use the version of defineClass() that takes a name parameter and is, therefore, more secure.

This method returns the newly created Class object.
Parameter
data – An array that contains the byte codes that define a class.
offset – The offset in the array of byte codes.
length – The number of byte codes in the array.

protected final Class defineClass(String name, byte[] data, int offset,int length);

protected final Class defineClass(String name, byte[] data, int offset, int length) method creates a Class object from the byte codes that define the class. Before the class can be used, it must be resolved. The method is intended to be called from an implementation of the loadClass() method.

This method returns the newly created Class object.
Parameter
name – The expected name of the class to be defined or null if it is not known. The class name should be qualified by its package name. The lack of an explicit package name specifies that the class is part of the default package.
data – An array that contains the byte codes that define a class.
offset – The offset in the array of byte codes.
length -The number of byte codes in the array.

protected final Class findLoadedClass(String name);

protected final Class findLoadedClass(String name) method finds the specified class that has already been loaded.
This method returns the Class object for the specified loaded class or null if the class cannot be found.
Parameter
name – The name of the class to be returned. The class name should be qualified by its package name. The lack of an explicit package name specifies that the class is part of the default package.

protected final Class findSystemClass(String name) throws ClassNotFoundException;

protected final Class findSystemClass(String name) throws ClassNotFoundException method finds and loads a system class if it has not already been loaded. A system class is a class that is loaded by the default class-loading mechanism from the local filesystem. An implementation of the loadClass() method typically calls this method to attempt to load a class from the locations specified by the CLASSPATH environment variable.

This method returns the Class object for the specified system class.
Parameter
name – The name of the class to be returned. The class name should be qualified by its package name. The lack of an explicit package name specifies that the class is part of the default package.

protected abstract Class loadClass(String name, boolean resolve) throws ClassNotFoundException;

protected abstract Class loadClass(String name, boolean resolve) abstract method loads the named class and returns its Class object. It is permitted and encouraged for an implementation to cache the classes it loads, rather than load one each time the method is called. An implementation of this method should do at least the following:

  • Load the byte codes that comprise the class definition into a byte[].
  • Call the defineClass() method to create a Class object to represent the class definition.
  • If the resolve parameter is true, call the resolveClass() method to resolve the class.

If an implementation of this method caches the classes that it loads, it is recommended that it use an instance of the java.util.Hashtable to implement the cache.

This method returns the Class object for the specified class.
Parameter
name – The name of the class to be returned. The class name should be qualified by its package name. The lack of an explicit package name specifies that the class is part of the default package.
resolve – Specifies whether or not the class should be resolved by calling the resolveClass() method.

protected final void resolveClass(Class c);

protected final void resolveClass(Class c) method resolves the given Class object. Resolving a class means ensuring that all of the other classes that the Class object references are loaded. Besides, all of the classes that they reference must be loaded, and so on, until all of the needed classes have been loaded.

The resolveClass() method should be called by an implementation of the loadClass() method when the value of the loadClass() method’s resolve parameter is true.

Parameter
c – The Class object for the class to be resolved.

protected final void setSigners(Class cl, Object[] signers);

protected final void designers(Class cl, Object[] signers) method specifies the objects that represent the digital signatures for this class.
Parameter
cl – The Class object for the class to be signed.
signers – An array of Objects that represents the signers of this class.

Apart from these ClassLoader class also has inherited methods from class- Object. They are as follows:

  • clone()
  • finalize()
  • hashCode()
  • notifyAll()
  • wait()
  • wait(long, int)
  • equals(Object)
  • getClass()
  • notify()
  • toString()
  • wait(long)

Share and Enjoy !

Leave a Reply

Your email address will not be published. Required fields are marked *