- references
- https://docs.oracle.com/javase/jndi/tutorial/beyond/misc/classloader.html
- https://www.amazon.com/Java-Language-Features-Modules-Expressions/dp/1484233476
- https://stackoverflow.com/questions/46494112/classloaders-hierarchy-in-java-9
- 2019 - Krzysztof Chruściel - Kilka wskazówek jak projektować użyteczne interfejsy
The Java ClassLoader is a part of the JRE that dynamically loads Java classes into the Java Virtual Machine.
Usually classes are only loaded on demand. Class Loader is a component with the Java Execution Engine which
loads the binary data from the .class files available in the classpath into the Method Area. Loading of a
class into the method area occurs only the first time when the class is referenced with in the running Java
application. For all other references the data is reused from the method area, unless the class has been UNLOADED.
All JVM (Java virtual machines) include one class loader that is embedded in the virtual machine. This embedded loader is called the primordial or bootstrap class loader. It is somewhat special because the VM (virtual machine) assumes that it has access to a repository of trusted classes which can be run by the virtual machine without verification.
When the JVM is started, three class loaders are used:
- Bootstrap class loader - loads the core Java libraries located in the
<JAVA_HOME>/jre/libdirectory. This class loader, which is part of the core JVM, is written in native code (mostly inC). Bootstrap class loader don't have any parents.- loads for example
Objectclass - represented by
nullin code (Object.class.getClassLoader() == null)
- loads for example
- Extensions class loader - loads the code in the extensions directories (
<JAVA_HOME>/jre/lib/ext, or any other directory specified by thejava.ext.dirssystem property). It is implemented by thesun.misc.Launcher$ExtClassLoaderclass. - System class loader - loads code found on
java.class.path, which maps to theCLASSPATHenvironment variable. It is implemented by thesun.misc.Launcher$AppClassLoaderclass.
- every Thread has a context classloader associated with it (unless it was created by native code)
- is set via the
Thread.setContextClassLoader()method- by default thread will inherit its context classloader from its parent Thread
- the hierarchy of threads is rooted at the primordial thread (the one that runs the program)
- the context class loader of the primordial thread is set to the class loader that loaded the application
- unless you explicitly change the thread's context class loader, its context class loader will be the application's class loader
ClassLoader in Java works on three principle:
- Delegation - when loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.
- Visibility - allows child class loader to see all the classes loaded by parent class loader, but parent class loader cannot see classes loaded by child.
- Uniqueness - allows to load a class exactly once, which is basically achieved by delegation (it ensures that child class loader doesn't reload the class already loaded by parent).
Remark: It is completely possible to write class loader which violates Delegation and Uniqueness principles and loads class by itself, its not something which is beneficial. You should follow all class loader principle while writing your own ClassLoader.
Remark: Each class loader has its namespace that stores the loaded classes. When a class loader loads a class, it searches the class based on FQCN (Fully Qualified Class Name) stored in the namespace to check whether or not the class has been already loaded. Even if the class has an identical FQCN but a different namespace, it is regarded as a different class. A different namespace means that the class has been loaded by another class loader.
Remark: The initial class is loaded with the help of public static main() method declared in your class.
- loading
- check if classes (
.class) match JVM specification, have well-defined structure- example -
CAFEBABEprefix- windows differs files by extensions (
.exe), JVM by prefix
- windows differs files by extensions (
- example -
- check java version
- example -
invokedynamiccannot be used with java 6,UnsupportedVersionException
- example -
- check if classes (
- linking
- verifying - check if classes are correct, otherwise
VerifyError- example - accessibility
- expensive - spring boot loads thousands of classes - every class have to be verified
-Xverify:none,-noverify
- preparing - default for static fields
- example - int -> 0
- basic structures for JVM
- resolving - constant pool has to become runtime constant pool
- optional - we dont need to load everything at once
- verifying - check if classes are correct, otherwise
- initializing
- static blocks (thread safe)
- classes are loaded into off-heap regions
- Runtime Constant Pool
- ByteCode
- Field/Method Data
- bootstrap class loader is implemented in the library code and in the virtual machine
(still represented by
nullin a program - backward compatibility) - no longer support for the extension mechanism
- extension class loader -> platform class loader
- platform class loader purpose: classes loaded by the bootstrap class loader have all permissions
by default - several classes did not need all permissions - they are de-privileged in JDK9 loaded by the
platform class loader
- loads for example:
java.sql
- loads for example:
- application class loader loads the application modules found on the module path and a few JDK
modules (for example
jdk.compiler,jdk.javadoc,jdk.jshell) - Before JDK9, the extension and the application class loader were an instance of the
java.net.URLClassLoaderclass. In JDK9, they are an instance of an internal JDK class. - apart from standard delegation: application -> platform -> bootstrap we have two more:
- application -> bootstrap
- platform -> application
- class loading mechanism:
- application class loader needs to load a class
- it searches modules defined to bootstrap and platform (can delegate directly)
- if the class is found in the module defined to bootstrap or platform it is loaded
- if a class is not found in a named module defined to bootstrap or platform, application delegates loading to platform
- if a class is not loaded, application scans the classpath
- if found - load as a inhabitant of unnamed module
- if not -
ClassNotFoundException
- java 9
sourceCompatibility = 9 - print all modules with classloaders
ModuleLayer layer = ModuleLayer.boot(); layer.modules().forEach(module -> { ClassLoader classLoader = module.getClassLoader(); String classLoaderName = isNull(classLoader) ? "bootstrap" : classLoader.getName(); System.out.println(classLoaderName + ": " + module.getName()); }); - output (may differ on different OS)
platform: jdk.localedata bootstrap: java.base bootstrap: java.security.sasl platform: jdk.zipfs app: jdk.jlink bootstrap: java.xml platform: jdk.crypto.ec platform: jdk.accessibility bootstrap: jdk.management.jfr app: jdk.compiler platform: jdk.naming.dns bootstrap: jdk.management bootstrap: java.naming bootstrap: jdk.naming.rmi platform: java.compiler bootstrap: java.instrument bootstrap: java.rmi app: jdk.internal.opt bootstrap: java.prefs app: jdk.jdeps bootstrap: java.management.rmi platform: jdk.crypto.mscapi app: jdk.jartool platform: java.security.jgss bootstrap: java.management platform: jdk.crypto.cryptoki platform: java.smartcardio platform: jdk.security.jgss bootstrap: java.desktop app: jdk.javadoc platform: jdk.charsets app: jdk.unsupported.desktop app: project // out project platform: jdk.security.auth platform: java.xml.crypto bootstrap: java.logging bootstrap: jdk.jfr bootstrap: java.datatransfer