In fact, the parental delegation model is not complicated. Customizing the ClassLoader is not difficult! You can search a lot of results from the Internet and then copy
you can use them. However, if you want to customize the ClassLoader every time you have to search someone else's article, and then copy, so obviously not. However, the custom class loader is not often used, it is easy to forget for a long time. I believe you often do not remember very loadClass
clearly findClass
, defineClass
these functions should I rewrite which one? What do they mostly do? This article roughly analyzes the various functions of the flow, the purpose is to let you read after, it is hard to forget! Or, extend your memory time to the custom ClassLoader! Customize whenever you want!
1. Parental delegation Model
There is a lot of information on the internet about parental assignment models. Let me just briefly describe it as a review.
1.1 What is a parental delegation model?
First, you need to know what the ClassLoader is. Simply put, the class loader class
loads the file into JVM
memory and into the object, based on the specified fully qualified name Class
. If you stand on JVM
the point of view, there are only two kinds of loaders:
Launch class loader ( Bootstrap ClassLoader
): implemented by the C++
language (for HotSpot
), which is responsible for <JAVA_HOME>\lib
loading the -Xbootclasspath
class library into memory in the path specified by the directory or parameter.
Other ClassLoader: Java
implemented by the language and inherited from the abstract class ClassLoader
. Such as:
- Extension class loader (
Extension ClassLoader
): Responsible for loading <JAVA_HOME>\lib\ext
java.ext.dirs
all class libraries in the path specified by the directory or system variable.
- Application class loader (
Application ClassLoader
). Responsible for loading the classpath
specified class library on the user classpath (), we can use this classloader directly. In general, if we do not have custom ClassLoader, the default is to use this loader.
The parent delegation model works by: If a class loader receives a request for a class load, it first does not attempt to load the class itself, but instead delegates the request to the parent class loader to complete. This is true for each classloader, and the ClassNotFoundException
child loader attempts to load itself only if the parent loader cannot find the specified class (that is) within its own search scope.
Parent delegation model for Class loader 1.2 Why do I need parental delegation models?
Why do we need parents to delegate the model? Imagine a scenario where there is no parental delegation model:
A hacker customizes a java.lang.String
class that String
has the same functionality as a system String
class, but modifies a function slightly. such as equals
functions, this function is often used, if in this function, the hacker added some "virus code". And is joined by a custom class loader JVM
. At this point, if there is no parental delegation model, JVM
it may be mistaken that the hacker's custom java.lang.String
class is the class of the system String
, causing the "virus code" to be executed.
With the parental delegation model, the hacker's custom java.lang.String
classes will never be loaded into memory. The java.lang.String
final custom ClassLoader cannot load the class because the top class loader first loads the system's class java.lang.String
.
You might think that I'm forcing a custom class inside a custom ClassLoader java.lang.String
, not by calling the parent loader. Really, that's doable. However, JVM
when judging whether an object is a type, it returns false if the actual type of the object differs from the class loader of the type to be compared.
To give a simple example:
ClassLoader1
, ClassLoader2
all load java.lang.String
classes, corresponding to Class1, Class2 objects. Then Class1
the object is not part ClassLoad2
of the object-loaded java.lang.String
type.
1.3 How do I implement a parental delegation model?
The principle of parent delegation model is simple and easy to implement. Each time it is loaded by delegating the parent class loader, the parent class loader fails to load and then loads itself. In fact ClassLoader
, the class default loadClass
method has been written for us, we do not have to write.
2. Custom class Loader 2. 1 Several important functions 2.1.1 LoadClass
loadClass
The default implementation is as follows:
public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false);}
Then look at the loadClass(String name, boolean resolve)
function:
Protected class<?> loadclass (String name,Boolean resolve)Throws classnotfoundexception{Synchronized (Getclassloadinglock (name)) {First, check if the class has already been loaded class C = Findloadedclass (name);if (c = =NULL) {Long T0 = System.nanotime ();try {if (Parent! =NULL) {c = parent.loadclass (name,FALSE); }else {c = findbootstrapclassornull (name);}}catch (classnotfoundexception e) {//ClassNotFoundException Thrown if class not found //from the Non-null parent class loader} if (c = = null) {//if still not found, then invoke Findclass in or Der //to find the class. long t1 = System.nanotime (); c = Findclass (name); //This is the defining class loader; record the stats Sun.misc.PerfCounter.getParentDelegationTime (). Addtime (T1-T0); Sun.misc.PerfCounter.getFindClassTime (). Addelapsedtimefrom (t1); Sun.misc.PerfCounter.getFindClasses (). increment (); }} if (Resolve) {resolveclass (c);} return C;}
As can be seen from the above code, the loadClass(String, boolean)
function is the implementation of the parent delegation model! The general process is as follows:
- First, check to see if the class with the specified name has already been loaded, and if it is loaded, it will not need to be loaded and returned directly.
- If this class has not been loaded, then determine if there is a parent loader, or if there is a parent loader, it is loaded (that is, called) by the parent loader
parent.loadClass(name, false);
. Or it is called by the ClassLoader bootstrap
to load.
- If both the parent loader and the
bootstrap
ClassLoader do not find the specified class, the method of the current ClassLoader is called findClass
to complete the class load.
In other words, if you customize the ClassLoader, you must override the findClass
Method!
2.1.1 Find Class
findClass
The default implementation is as follows:
protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name);}
As you can see, the function of an abstract class ClassLoader
findClass
defaults to throwing an exception. As we know earlier, loadClass
when the parent loader is unable to load the class, it invokes the function in our custom ClassLoader findeClass
, so we have to loadClass
implement this function to convert a specified class name to an Class
object.
This is good if it is a byte array to read a class of the specified name. But how do you convert a byte array to an Class
object? It is simple to Java
provide a defineClass
method by which a byte array can be converted to a class object.
2.1.1 DefineClass
defineClass
The main functions are:
Converts a byte array to an Class
object, which is the class
final byte array after the file is read. For example, if the class
file is encrypted, it needs to be decrypted and passed into the function as a parameter defineClass
.
defineClass
The default implementation is as follows:
protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError { return defineClass(name, b, off, len, null);}
2.2 Function Call procedure
The function call procedure mentioned in the previous section is as follows:
Custom Function Call Procedure 2.3 Simple example
First, we define a generic class to load Java
: Test.java
. Put com.huachao.cl
under the package:
package com.huachao.cl;public class Test { public void hello() { System.out.println("恩,是的,我是由 " + getClass().getClassLoader().getClass() + " 加载进来的"); }}
Attention:
If you are creating directly within the current project, Test.java
please copy the files and delete them after compiling Test.class
Test.java
. Because if Test.class
stored in the current project, according to the parent delegation model, it is loaded through the ClassLoader sun.misc.Launcher$AppClassLoader
. In order for our custom class loader to load, we put the Test.class file into another directory.
In this example, our Test.class file contains the following directories:
class file Directory
The next step is to customize our ClassLoader:
Import Java.io.FileInputStream;Import Java.lang.reflect.Method;PublicClassMain {StaticClassMyclassloaderExtendsClassLoader {Private String ClassPath;PublicMyclassloader(String ClassPath) {This.classpath = ClassPath; }PrivateByte[] Loadbyte (String name)Throws Exception {name = Name.replaceall ("\\.","/"); FileInputStream FIS =New FileInputStream (ClassPath +"/" + name +". Class");int len = fis.available ();byte[] data =NewByte[len]; Fis.read (data); Fis.close ();return data; }Protected class<?> Findclass (String name)Throws ClassNotFoundException {try {byte[] data = loadbyte (name);Return defineclass (name, data,0, data.length); } catch (Exception e) {e.printstacktrace (); throw new classnotfoundexception ();}} }; public static void main (String args[]) throws Exception {myclassloader classLoader = new Myclassloader ( "d:/test"); Class clazz = Classloader.loadclass ( "com.huachao.cl.Test"); Object obj = clazz.newinstance (); Method HelloMethod = Clazz.getdeclaredmethod ( "hello", null); Hellomethod.invoke (obj, null);}
The results of the final operation are as follows:
class Main$MyClassLoader 加载进来的
Java custom class loader and parental delegation model