Article catalog
1. The whole process of class loading
Why study the whole process of class loading? – helps to understand the JVM running process – more in-depth understanding of java dynamics (hot deployment and dynamic loading) to improve program flexibility.
Class loading mechanism – the JVM loads the class file into memory, verifies, parses and initializes the data, and finally forms a Java type process that can be directly used by the JVM·

1.1 loading
Load the bytecode content of the class file into memory, convert these static data into the runtime data structure in the method area, and generate a java.lang.Class object representing this class in the heap as the access entry for the class data in the method area. This process requires the participation of the class loader.

1.2 links
The process of merging the binary code of a Java class into the running state of the JVM (1) Verification: ensure that the loaded class information complies with the JVM specification and there are no security problems. (2) Preparation: the stage of formally allocating memory for class variables (static variables) and setting the initial value of class variables. These memory will be allocated in the method area (3) Resolution: the process of replacing symbolic references in the virtual machine constant pool with direct references
1.3 initialization
• the initialization phase is the process of executing class constructor () methods. Class constructor () methods are automatically collected by the compiler The assignment actions of all class variables in the class are combined with the statements in the static statement block (static block). • when initializing a class, if you find that its parent class has not been initialized, you need to initialize its parent class first • virtual chance ensures that the () methods of a class are locked and synchronized correctly in a multithreaded environment.

Active reference of class (class initialization must occur) – new object of a class – call static members (except final constants) and static methods of the class – use the methods of the java.lang.reflect package to make reflection calls to the class – when the virtual machine starts and java Hello, the Hello class will be initialized. To put it bluntly, start the class where the main method is located first - when initializing a class, if its parent class is not initialized, its parent class will be initialized first • class passive reference (class initialization does not occur) – when accessing a static domain, only the class that actually declares the domain will be initialized • referencing a static variable of a parent class through a subclass will not cause subclass initialization – defining a class reference through an array does not trigger the initialization of this class – reference constants do not trigger the initialization of this class (constants are stored in the constant pool of the calling class at the compilation stage)
The test cases are as follows
package com.bigdataBC.jvm; public class demo01 { static{ System.out.println("initiate static Demo01"); } public static void main(String[] args) throws Exception { System.out.println("Demo01 of main method!"); System.out.println(System.getProperty("java.class.path")); //Active reference // new A(); // System.out.println(A.width); // Class.forName("com.bjsxt.test.A"); //Passive reference // System.out.println(A.MAX); // A[] as = new A[10]; System.out.println(B.width); } } class B extends A { static { System.out.println("initiate static B"); } } class A extends A_Father { public static int width=100; //Static field public static final int MAX=100; static { System.out.println("Static initialization class A"); width=300; } public A(){ System.out.println("establish A Object of class"); } } class A_Father extends Object { static { System.out.println("initiate static A_Father"); } }
2. Function of class loader
Role of class loader – load the bytecode contents of the class file into memory and convert these static data into methods The runtime data structure in the area generates a java.lang.Class representing this class in the heap Object as the access entry of class data in the method area.

Class cache • the standard Java SE class loader can find classes as required, but once a class is loaded into the class loader It will remain loaded (cached) for a period of time. However, the JVM garbage collector can recycle These Class objects.
3. java.class.ClassLoader class
- effect:
- The basic responsibility of the java.lang.ClassLoader class is based on a specified class name, Find or generate its corresponding byte code, and then define one from these byte codes Java class, that is, an instance of java.lang.Class class.
- In addition, ClassLoader is also responsible for loading resources required by Java applications, such as images and text Pieces and configuration files, etc.
- The related method getParent() returns the parent class loader of this class loader. loadClass(String name) loads a class named name, and the returned result is an instance of java.lang.Class. findClass(String name) finds a class named name, and the returned result is an instance of the java.lang.Class class class. findLoadedClass(String name) finds a loaded class with the name name name, and the returned result is an instance of the java.lang.Class class class. defineClass(String name, byte[] b, int off, int len) converts the contents of byte array b into Java classes, and the returned result is an instance of java.lang.Class. This method is declared final. Resolveclass (class <? > C) links the specified Java class. For the methods given above, the value of the name parameter representing the class name is the binary name of the class. Note the representation of the inner class, such as com.example.Sample
4. Hierarchy of class loader (tree structure)
- bootstrap class loader – it is used to load the core library of Java (JAVA_HOME/jre/lib/rt.jar, or under the sun.boot.class.path path path) Content), which is implemented in native code (this is written in C + +, and the three loaders described later are written in Java), and does not inherit from java.lang.ClassLoader.

– load extension classes and application class loaders. And specify their parent class loader.
- extensions class loader – the extension library used to load Java (JAVA_HOME/jre/ext/*.jar, or the contents in the java.ext.dirs path). The implementation of the Java virtual machine provides an extension library directory. This class loader finds and loads Java in this directory Class.

– implemented by sun.misc.Launcher$ExtClassLoader
- application class loader - it is based on the classpath of the Java application, java.class.path) to load Java classes. Generally speaking, Java application classes are loaded by it. – implemented by sun.misc.Launcher$AppClassLoader
- Custom class loader – developers can inherit the java.lang.ClassLoader class Implement your own class loader to meet some special needs.

Although the above figure seems to be a parent-child relationship, it is not inheritance, but a combination relationship.

5. Proxy mode of class loader
proxy pattern - give it to other loaders to load the specified class • parental entrustment mechanism – when a specific class loader receives a request to load a class, it first delegates the loading task Entrusted to the parent loader, trace back in turn until the highest grandparent, if the parent loader If the class loading task can be completed, it will be returned successfully; Only the parent loader cannot complete this load Only load the task by yourself. – the two parent delegation mechanism is to ensure the type safety of the Java core library. • this mechanism ensures that users can not define java.lang.Object classes themselves. – class loader is not only used to load classes, but also the most basic security barrier. • parental entrustment mechanism is a kind of agency model – not all class loaders use a two parent delegation mechanism. – the tomcat server class loader also uses the proxy mode. The difference is that it first tries to load a class, and then proxy it to the parent class loader if it cannot be found. This is in the reverse order of the general class loader
6. java.class.ClassLoader class API
• relevant methods – getParent() returns the parent class loader of this class loader. – loadClass(String name) loads a class named name, and the returned result is an instance of the java.lang.Class class class. • this method is responsible for loading the class with the specified name. First, it will look for the loaded class. If it is not found; Load from parent ClassLoader[ExtClassLoader]; as If it is not loaded, try to load it from Bootstrap ClassLoader (findbootstrap classornull method). If it still fails to load, load it yourself. If also If it cannot be loaded, an exception ClassNotFoundException is thrown. • if you want to change the loading order of the class, you can override this method; – findClass(String name) finds a class named name, and the returned result is an instance of the java.lang.Class class class. – findLoadedClass(String name) finds the loaded class with the name name name, and the returned result is the real name of the java.lang.Class class class Example. – defineClass(String name, byte[] b, int off, int len) converts the contents of byte array b into Java classes, and the returned result is An instance of the java.lang.Class class. This method is declared final. – resolveclass (class <? > C) links the specified Java class. – – the value of the name parameter representing the class name is the name of the class. Note the representation of the inner class, such as com.example.Sample
1 and com.example.SampleInner, etc.
7. Custom class loader
• file system class loader • process of customizing class loader: – 1. First check whether the requested type has been loaded into the namespace by this class loader. If it has been loaded, return directly; Otherwise, go to step 2 – 2. Delegate the class loading request to the parent class loader (to be more precise, it should be the parent class loader. All kinds of loaders in a real virtual machine will eventually present a tree structure). If the parent class is added If the loader can complete, the Class instance loaded by the parent Class loader is returned; Otherwise, go to step 3 – 3. Call the findClass (...) method of this class loader to try to obtain the corresponding bytecode. If the bytecode is obtained, call defineClass (...) to import the type into the method area; as If the corresponding bytecode cannot be obtained or fails for other reasons, an exception is returned to loadClass (...), and loadClass (...) throws the exception and terminates the loading process (Note: here There is more than one exception type). – note: the JVM does not consider the same class loaded by two class loaders as the same class.
7.1 file loader
First prepare a compiled class file

Define a file class loader
package com.bigdataBC.loader; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * Custom file system class loader * */ public class FileSystemClassLoader extends ClassLoader { //com.bigdataBC.loader.HelloWorld --> d:/myjava/ com/bigdataBC/loader/HelloWorld.class private String rootDir; public FileSystemClassLoader(String rootDir){ this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); //You should first query whether this class has been loaded. If it has been loaded, the loaded class will be returned directly. If not, load a new class. if(c!=null){ return c; }else{ ClassLoader parent = this.getParent(); try { c = parent.loadClass(name); //Delegate to parent class load } catch (Exception e) { // e.printStackTrace(); } if(c!=null){ return c; }else{ byte[] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ c = defineClass(name, classData, 0,classData.length); } } } return c; } private byte[] getClassData(String classname){ //com.bigdataBC.loader.HelloWorld --> d:/myjava/ com/bigdataBC/loader/HelloWorld.class String path = rootDir +"/"+ classname.replace('.', '/')+".class"; // IOUtils, which can be used to convert the data in the stream into a byte array InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try{ is = new FileInputStream(path); byte[] buffer = new byte[1024]; int temp=0; while((temp=is.read(buffer))!=-1){ baos.write(buffer, 0, temp); } return baos.toByteArray(); }catch(Exception e){ e.printStackTrace(); return null; }finally{ try { if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(baos!=null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
Test class
package com.bigdataBC.loader; /** * Test the custom FileSystemClassLoader * */ public class demo { public static void main(String[] args) throws Exception{ FileSystemClassLoader loader = new FileSystemClassLoader("d:/myjava"); FileSystemClassLoader loader2 = new FileSystemClassLoader("d:/myjava"); Class<?> c = loader.loadClass("com.bigdataBC.loader.HelloWorld"); Class<?> c2 = loader.loadClass("com.bigdataBC.loader.HelloWorld"); Class<?> c3 = loader2.loadClass("com.bigdataBC.loader.HelloWorld"); Class<?> c4 = loader2.loadClass("java.lang.String"); Class<?> c5 = loader2.loadClass("com.bigdataBC.loader.demo"); System.out.println(c.hashCode()); System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); //The same class is loaded by different loaders, and the JVM considers it to be a different class System.out.println(c4.hashCode()); System.out.println(c3.getClassLoader()); //Custom class loader System.out.println(c4.getClassLoader()); //bootstrap class loader System.out.println(c5.getClassLoader()); //System default classloader } }

7.2 network loader
Similar to the above example, it is just to replace the local path with the URL path
package com.bjsxt.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; /** * Network class loader * */ public class NetClassLoader extends ClassLoader { //com.bigdataBC.loader.HelloWorld --> www.xxx.cn/myjava/ com/bigdataBC/loader/HelloWorld.class private String rootUrl; public NetClassLoader(String rootUrl){ this.rootUrl = rootUrl; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); //You should first query whether this class has been loaded. If it has been loaded, the loaded class will be returned directly. If not, load a new class. if(c!=null){ return c; }else{ ClassLoader parent = this.getParent(); try { c = parent.loadClass(name); //Delegate to parent class load } catch (Exception e) { // e.printStackTrace(); } if(c!=null){ return c; }else{ byte[] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ c = defineClass(name, classData, 0,classData.length); } } } return c; } private byte[] getClassData(String classname){ //com.bigdataBC.loader.HelloWorld --> www.xxx.cn/myjava/ com/bigdataBC/loader/HelloWorld.class String path = rootUrl +"/"+ classname.replace('.', '/')+".class"; // IOUtils, which can be used to convert the data in the stream into a byte array InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try{ URL url = new URL(path); is = url.openStream(); byte[] buffer = new byte[1024]; int temp=0; while((temp=is.read(buffer))!=-1){ baos.write(buffer, 0, temp); } return baos.toByteArray(); }catch(Exception e){ e.printStackTrace(); return null; }finally{ try { if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(baos!=null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
7.3 encryption and decryption loader (reverse operation, DES symmetric encryption and decryption)
A simple encryption tool class
package com.bjsxt.test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * Encryption tool class * */ public class EncrptUtil { public static void main(String[] args) { encrpt("d:/myjava/com/bigdataBC/loader/HelloWorld.class", "d:/myjava/temp/HelloWorld.class"); } public static void encrpt(String src, String dest){ FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(src); fos = new FileOutputStream(dest); int temp = -1; while((temp=fis.read())!=-1){ fos.write(temp^0xff); //Reverse operation } } catch (Exception e) { e.printStackTrace(); }finally{ try { if(fis!=null){ fis.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(fos!=null){ fos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }

After running the tool class, a new encrypted bytecode file is generated under temp. So how to decrypt it? Then define a corresponding decryption tool class:
package com.bjsxt.test; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * Class loader that loads the encrypted class bytecode in the file system * */ public class DecrptClassLoader extends ClassLoader { //com.bigdataBC.loader.HelloWorld --> d:/myjava/ com/bigdataBC/loader/HelloWorld.class private String rootDir; public DecrptClassLoader(String rootDir){ this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); //You should first query whether this class has been loaded. If it has been loaded, the loaded class will be returned directly. If not, load a new class. if(c!=null){ return c; }else{ ClassLoader parent = this.getParent(); try { c = parent.loadClass(name); //Delegate to parent class load } catch (Exception e) { // e.printStackTrace(); } if(c!=null){ return c; }else{ byte[] classData = getClassData(name); if(classData==null){ throw new ClassNotFoundException(); }else{ c = defineClass(name, classData, 0,classData.length); } } } return c; } private byte[] getClassData(String classname){ //com.bigdataBC.loader.HelloWorld --> d:/myjava/ com/bigdataBC/loader/HelloWorld.class String path = rootDir +"/"+ classname.replace('.', '/')+".class"; // IOUtils, which can be used to convert the data in the stream into a byte array InputStream is = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try{ is = new FileInputStream(path); int temp = -1; while((temp=is.read())!=-1){ baos.write(temp^0xff); //The reverse operation is equivalent to decryption } return baos.toByteArray(); }catch(Exception e){ e.printStackTrace(); return null; }finally{ try { if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(baos!=null){ baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
package com.bjsxt.test; /** * Test simple encryption and decryption (inversion) operation * */ public class Demo04 { public static void main(String[] args) throws Exception { //Test reverse operation // int a = 3; //0000011 // System.out.println(Integer.toBinaryString(a^0xff)); //The encrypted class file cannot be loaded by the normal class loader, and the classFormatError is reported // FileSystemClassLoader loader = new FileSystemClassLoader("d:/myjava/temp"); // Class<?> c = loader.loadClass("HelloWorld"); // System.out.println(c); DecrptClassLoader loader = new DecrptClassLoader("d:/myjava/temp"); Class<?> c = loader.loadClass("com.bigdataBC.loader.HelloWorld"); System.out.println(c); } }

8. Thread context class loader
• problems with the two parent delegation mechanism and the default class loader – generally, ensure that other classes associated with the same class are loaded by the class loader of the current class. For example, if ClassA itself is found under Ext, some classes from new in it can only be found with Ext (not a lower level), so there are Some apps can be found, but they can't be found. – JDBC API, which has the driven part (mysql/sql server) implemented. Our JDBC APIs are loaded by Boot or Ext, but If the JDBC driver is loaded by Ext or App, the driver may not be found. In the Java field, in fact, it can be divided into Api+SPI( Service Provide Interface (provided by specific manufacturers) will encounter this problem. – common SPIs include JDBC, JCE, JNDI, JAXP, JBI, etc. These SPI interfaces are provided by the Java core library, such as the SPI interface of JAXP The semantics are contained in the javax.xml.parsers package. SPI interface is a part of Java core library and is loaded by boot class loader; SPI implemented Java classes are generally loaded by the system class loader. The bootstrap class loader cannot find the SPI implementation class because it only loads the Java core library . • usually, when you need to dynamically load resources, you have at least three classloaders to choose from: – 1. System ClassLoader or application ClassLoader – 2. Current ClassLoader – 3. Current thread class loader • the current thread class loader is designed to abandon the parent delegate load chain mode. – each thread has an associated context class loader. If you use the new Thread() method to generate a new thread, the new thread will inherit its parent thread Class loaders are described below. If the program does not make any changes to the thread context class loader, all threads in the program will use the system class loader as the upper class Class loaders are described below. • Thread.currentThread().getContextClassLoader()
package com.bjsxt.test; /** * Test of thread context class loader */ public class Demo05 { public static void main(String[] args) throws Exception { ClassLoader loader = Demo05.class.getClassLoader(); System.out.println(loader); ClassLoader loader2 = Thread.currentThread().getContextClassLoader(); System.out.println(loader2); Thread.currentThread().setContextClassLoader(new FileSystemClassLoader("d:/myjava/")); System.out.println(Thread.currentThread().getContextClassLoader()); Class<Demo01> c = (Class<Demo01>) Thread.currentThread().getContextClassLoader().loadClass("com.bigdataBC.loader.HelloWorld"); System.out.println(c); System.out.println(c.getClassLoader()); } }

9. Class loading mechanism of Tomcat server
• everything is for safety! – TOMCAT cannot use the system default class loader. • if TOMCAT runs your WEB project using the system's classloader, it's quite dangerous. You can So direct is unscrupulous is the various directories of the operating system. • for running in Java EE ™ For the Web application in the container, the implementation of class loader is the same as one Java applications are different. • each Web application has a corresponding class loader instance. This class loader also uses the proxy module The difference is that it first attempts to load a Class. If it cannot be found, delegate it to the parent class loader. This is in the reverse order of the general class loader . But also to ensure security, so that the core library is not within the query scope. • for security, TOMCAT needs to implement its own class loader. • I can restrict you to write the class in the specified place, otherwise I won't load it for you!

Introduction to OSGI principle • OSGi ™ Is a dynamic module system on Java. It provides service-oriented and component-based services for developers Line environment and provide a standard way to manage the software life cycle. • OSGi has been implemented and deployed on many products and has been widely supported in the open source community. Eclipse It is built based on OSGi technology. • principle: – each module in OSGi contains Java packages and classes. A module can declare the required imports on which it depends Java packages and classes of other modules of (import) can also be declared for export (through import package)( Export) own packages and classes for use by other modules (through export package). That means you need to be able to Enough to hide and share some Java packages and classes in a module. This is achieved through OSGi's unique class loader mechanism Implemented. Each module in OSGi has a corresponding class loader. It is responsible for loading the data contained in the module itself java packages and classes. When it needs to load the classes of the java core library (packages and classes beginning with java), it will proxy to The parent class loader (usually the startup class loader) to complete. When it needs to load the imported Java class, it will Proxy to the module exporting this Java class to complete the loading. Modules can also explicitly declare some Java packages and classes. You must Must be loaded by the parent loader. You only need to set the system property org.osgi.framework.bootselection The value of