The JVM loads a Class file in three main processes: Loading, Linking, and Initialzing
1. Loading
This process involves loading the class file into memory, understanding the parent delegate model and the ClassLoader
-
Class loader
The JDK provides three classLoaders that are internal classes for the Launcher. The screenshots are in Sun.misc.Launcher
BootClassLoader Loading range sun.boot.class.path
ExtClassLoader loads the scope java.ext.dirs
AppClassLoader loads the scope java.class.path
CustomClassLoader You can customize the loading range
-
Parental delegation model
Graph BT A(.class)-->B(CustomClassLoader)-- >Z(CustomClassLoader) B(CustomClassLoader)-- not loaded -->C(AppClassLoader)-- loaded -->Z((return result)) C(AppClassLoader)-- not loaded -->D(ExtClassLoader)-- >Z((return result)) D(ExtClassLoader)-- not loaded -->E(BootClassLoader)-- loaded -->Z((return result)) E(BootClassLoader)== not loaded -->Z(return result) E(BootClassLoader)== Cannot load by itself ==>D(ExtClassLoader) D(ExtClassLoader)== Can load by itself ===>Z((result returned)) D(ExtClassLoader)== Cannot load by itself ==>C(AppClassLoader) C(AppClassLoader)== Can load by itself ===>Z((result returned)) C(AppClassLoader)== Cannot load by itself ===>B(CustomClassLoader) B(CustomClassLoader)== Can load by itself ===>Z((return result)) B(CustomClassLoader)== cannot load ===> exception ((ClassNotFoundException))
1, to prevent repeated loading of the same.class, through the delegate to ask the above, loaded, do not need to load again. Ensure data security. 2. Ensure that core.class cannot be tampered with. By delegating, you’re not going to tamper with the core clas, you’re not going to load it, you’re not going to load the same.class object. Different loaders loading the same.class are not the same class object. This ensures Class execution security.
-
Parent delegate source code representation
/** * Class files are loaded recursively. The findClass() method can be overridden to implement its own ClassLoader
protectedClass<? > loadClass(String name,boolean resolve) throws ClassNotFoundException{
synchronized (getClassLoadingLock(name)) {
// Check if the class file is loaded, return if it is loaded, and continue loading if it is notClass<? > c = findLoadedClass(name);if (c == null) {
long t0 = System.nanoTime();
try {
if(parent ! =null) {
//parent is loaded with the loadClass method
c = parent.loadClass(name, false);
} else {
// If there is no parent, it will be loaded by BootClassLoaderc = findBootstrapClassOrNull(name); }}catch (ClassNotFoundException e) {
}
if (c == null) {
// If the current ClassLoader does not find it, load the class file
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); }}if (resolve) {
resolveClass(c);
}
returnc; }}Copy the code
- The custom this
public class CustomClassLoader extends ClassLoader{
//
@Override
protectedClass<? > findClass(String name)throws ClassNotFoundException{
try {
File file = new File(name);
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int len;
byte[] buffer = new byte[1024];
while((len = fis.read(buffer)) ! = -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
byte[] bytes = byteArrayOutputStream.toByteArray(); Class<? > clazz = defineClass(null, bytes, 0, bytes.length);
System.out.println(clazz);
return clazz;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Test
public void classLoaderTest(a) throws Exception{
CustomClassLoader customClassLoader = newCustomClassLoader(); Class<? > clazz = customClassLoader.loadClass("D:\\zyouke_git\\zyouke\\java_base\\out\\production\\java_base\\spi\\IHelloSpi.class"); System.out.println(clazz); }}Copy the code
- How do I break the parental delegation model
- LoadClass ()
- Custom ClassLoader that specifies parent by calling super(parent) in the constructor
2. Linking
Linking link can be divided into three stages: Vertification, Preparation and Resolution. Vertification: Verifies that the Class file complies with JVM specifications. Preparation: Assigns default values to static member variables. Resolution: Interprets symbolic references to classes, methods, attributes, etc. as direct references; Symbolic references in the constant pool are interpreted as direct references to memory addresses such as Pointers and offsets
3. Initialzing
Call the initialization code Clint to assign initial values to static member variables.
Here are the five cases that must be initialized:
1, The new getstatic putstatic Invokestatic instruction, except to access final variables. 2, when java.lang.Reflect makes a reflection call to a class. 3. When initializing a child class, the parent class must be initialized. 4. When the VM starts, the executed main class must be initialized. 5, a dynamic language support Java. Lang. Invoke the MethodHandler interpretation results for REF_getstatic REF_putstatic REF_invokestatic method handles, the class must be initialized.
How and why does extended Tomcat break the parent delegation model
-
URLClassLoader commonLoader catalinaLoader, sharedLoader are based on the URLClassLoader created.
public static void main(String[] args) throws Exception{ // Create an array of urls containing jars from maven libraries URL[] urlArr = new URL[]{new URL("File: C: / Users/Administrator/m2 / repository/org/objenesis/objenesis / 2.2 / objenesis - 2.2. The jar." ")}; URLClassLoader urlClassLoader = new URLClassLoader(urlArr,Thread.currentThread().getContextClassLoader()); / / org. Objenesis. ObjenesisBase is the class under the jarClass<? > clazz = urlClassLoader.loadClass("org.objenesis.ObjenesisBase"); System.out.println(clazz.getClassLoader()); System.out.println(clazz); } // Print the result // Load the classLoader of the class java.net.URLClassLoader@e2d56bf //class org.objenesis.ObjenesisBase Copy the code
-
Tomcat Custom commonLoader, catalinaLoader, sharedLoader
//org.apache.catalina.startup.Bootstrap#initClassLoaders // called when Tomcat is started private void initClassLoaders(a) { try { /** * Create common.loader jar from catalina.properties; /** * create common.loader jar from catalina.properties; Java.lang.classloader #getSystemClassLoader() returns the classLoader as parent */ commonLoader = createClassLoader("common".null); if( commonLoader == null ) { commonLoader=this.getClass().getClassLoader(); } /** * catalinaLoader, URLClassLoader will be returned using the jar configured by catalina.properties * cserver.loader, parent will use commonLoader */ catalinaLoader = createClassLoader("server", commonLoader); /** * catalinaLoader, which uses the * shared.loader jar from catalina.properties to build URLClassLoader return, parent uses commonLoader */ sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { handleThrowable(t); log.error("Class loader creation threw exception", t); System.exit(1); }}Copy the code
-
WebappClassLoader
One Tomcat may deploy multiple web applications. Different Web applications may rely on different versions of the same third-party library. To ensure that the class libraries of each Web application are independent, class isolation is required. Tomcat’s custom class loader, WebAppClassLoader, solves this problem. Each Web application has a Corresponding Instance of WebAppClassLoader. Different instances load different classes, and Web applications are isolated from each other through their own class loaders.
The ClassLoaderfindClass and loadClass methods are overridden in the parent WebappClassLoaderBase class
// omit some code to explain key parts publicClass<? > findClass(String name)throwsClassNotFoundException { Class<? > clazz =null; try { try { // Start by looking for classes in the Web application directory clazz = findClassInternal(name); } catch(AccessControlException ace) { throw new ClassNotFoundException(name, ace); } catch (RuntimeException e) { throw e; } if ((clazz == null) && hasExternalRepositories) { try { // Can not find the class in the Web application directory, the parent class load clazz = super.findClass(name); } catch(AccessControlException ace) { throw new ClassNotFoundException(name, ace); } catch (RuntimeException e) { throwe; }}// If the parent class cannot be loaded, throw an exception if (clazz == null) { throw newClassNotFoundException(name); }}catch (ClassNotFoundException e) { throwe; }}Copy the code
publicClass<? > loadClass(String name,boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // (0) Check whether the local cache exists clazz = findLoadedClass0(name); if(clazz ! =null) { return (clazz); } // (1) load it from the system clazz = findLoadedClass(name); if(clazz ! =null) { return (clazz); } String resourceName = binaryNameToPath(name, false); // Get the Java class loader and load it ClassLoader javaseLoader = getJavaseClassLoader(); if (tryLoadingFromJavaseLoader) { try { clazz = javaseLoader.loadClass(name); if(clazz ! =null) { return(clazz); }}catch (ClassNotFoundException e) { } } try { // Try to search the local directory for the class and load it clazz = findClass(name); if(clazz ! =null) { return(clazz); }}catch (ClassNotFoundException e) { } // No exception was thrown throw new ClassNotFoundException(name); } Copy the code