• 周六. 10 月 5th, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

【java_ The relationship between class loader, parent delegation mechanism and overall delegation mec

King Wang

1 月 3, 2022

Class loader and parent delegation mechanism 、 The relationship of the whole Commission mechanism

One . Class loader

 Insert picture description here

1.1 Class loader rt.jar in sun.misc.Launcher.class

public class Launcher {

static class AppClassLoader extends URLClassLoader {
}
static class ExtClassLoader extends URLClassLoader {
}
}

JVM When loading any class , Delegate to top loader Bootstrap ClassLoader, Bootstrap Will load Launcher.class( No compilation required , It exists directly in rt.jar in )
That is to say Bootstrap Start up , AppClassLoader,ExtClassLoader Has become available

1.2 The base class of two kinds of loaders URLClassLoader

public class URLClassLoader extends SecureClassLoader implements Closeable {
}
public class SecureClassLoader extends ClassLoader {
}

1.3 native Bottom loading .class file ClassLoader.defineClass()

 protected final Class<?> defineClass(String name, byte[] b, int off, int len){

return defineClass(name, b, off, len, null);
}

 Insert picture description here
native Method to read an array of bytes , That’s what we usually call bytecode files , You can also read a resource based on the byte stream
native Native supports loading compiled .class file , In network transmission .class file , Even myself new Out of the byte array

Two . Parent delegate mechanism

2.1 One of the two parents appointed : loadClass()

2.1.1 ClassLoader.loadClass()
 public Class<?> loadClass(String name) throws ClassNotFoundException {

return loadClass(name, false);
}
 // native Read whether the class has been loaded 
private native final Class<?> findLoadedClass0(String name);
 protected Class<?> loadClass(String name, boolean resolve) {

// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {

try {

// Recursively looking for the parent loader 
if (parent != null) {

c = parent.loadClass(name, false);
else
//parent == null when Access to the top loader 
c = findBootstrapClassOrNull(name);
} catch (ClassNotFoundException e) {

}
if (c == null) {

// findClass find class File will be called after defineClass Method to import bytecode into method area , Caching results at the same time 
c = findClass(name);
}
}
}

AppClassLoader and ExtClassLoader All use the rule of changing parental delegation

2.1.2 The execution directory of different classloaders
  • start-up (Bootstrap) Class loader : Responsible for loading %Java_Home%/lib The following core class library or -Xbootclasspath Option specified jar package . from native Method to implement the loading process , The program can’t get the loader directly , Nothing can be done with it .
  • Expand (Extension) Class loader : The extension class loader is created by sun.misc.Launcher.ExtClassLoader Realized . Responsible for loading %Java_Home%/lib/ext Or by system variable -Djava.ext.dir Specify the class library in the location . The program can access and use the extension class loader .
  • System (System) Class loader : The system class loader is created by sun.misc.Launcher.AppClassLoader Realized , Also called application class loader . Responsible for loading system classpath -classpath or -Djava.class.path The class library in the directory indicated by the variable . The program can access and use the system classloader .

2.2 Two of them are appointed by parents :findClass()

2.2.1 ClassLoader.findClass()
 protected Class<?> findClass(String name) throws ClassNotFoundException {

throw new ClassNotFoundException(name);
}
2.2.2 AppClassLoader and ExtClassLoader Of findClass()
 // Search path 
private final URLClassPath ucp;
 protected Class<?> findClass(final String name) {

final Class<?> result;
result = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>(){

public Class<?> run() throws ClassNotFoundException {

String path = name.replace('.', '/').concat(".class");
// Find your own path class file 
Resource res = ucp.getResource(path, false);
if (res != null) {

// If you find it, inject 
return defineClass(name, res);
} else {

return null;
}
}
}, acc);
if (result == null) {

throw new ClassNotFoundException(name);
}
return result;
}

2.3 Why a parental delegation mechanism is needed ?

2.3.1 Solve the problem of dependence

Make sure that the core class loads first , The core class loads , Other user-defined classes don’t have dependency problems .

2.3.2. Don’t reload , Ensure that the core class is not tampered with

Bootstrap ClassLoader It’s a classloader that’s invisible to users , It’s also the top loader ,%Java_Home%/lib The following core classes will load first , If the user defines java.lang.Integer, The program can only use AppClassLoader To load , Once executed to its parent class URLClassLoader Of findClass()` The statement in , Will skip loading the class with the same name

 Class<?> c = findLoadedClass(name);

It is worth mentioning that , Class loader loads… In the network java.lang.Integer, Another mechanism is needed to detect

URLClassLoader extends SecureClassLoader, jdk Self contained classLoader All have this ability

 public final Class<?> loadClass(String name, boolean resolve){

// First check if we have permission to access the package. This
// should go away once we've added support for exported packages.
SecurityManager sm = System.getSecurityManager();
if (sm != null) {

int i = name.lastIndexOf('.');
if (i != -1) {

sm.checkPackageAccess(name.substring(0, i));
}
}
return super.loadClass(name, resolve);
}

Using a custom class loader does not inherit SecureClassLoader It can be realized with The core class coexists with the same name ,

reason :JVM The identity class is exactly the same , You need a full name limit + Load the class loader of this class

But generally not , So there is a saying on the Internet :

It is recommended to customize class loader inheritance URLClassLoader One of the reasons is to inherit SecureClassLoader Try to be as safe as possible .

2.3.3 Can you not follow the parental delegation ?

Certainly.

  • Customize a classloader and override loadClass Can not follow
  • A simpler way , Use Class.forName( All names are limited ) , In fact, it’s the overall delegation mechanism

3、 … and . JVM How to load compiled .class file

Class.forName()

 @CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {

Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
 private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
  • By default, the caller’s ClassLoader To load a class

  • You can also specify the specified classloader
     Insert picture description here

ClassLoader.loadClass()

 public Class<?> loadClass(String name) throws ClassNotFoundException {

return loadClass(name, false);
}
 protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{

synchronized (getClassLoadingLock(name)) {

// Find out from the cache if the class is loaded 
Class<?> c = findLoadedClass(name);
if (c == null) {

try {

if (parent != null) {

c = parent.loadClass(name, false);
}
} catch (ClassNotFoundException e) {

// Throw exceptions to prove the present ClassLoader The target class does not exist in the directory 
// Use catch The scheduler continues to execute 
}
if (c == null) {

// findClass Expose to subclass implementation , Make it possible to break parental delegation 
c = findClass(name);
}
}
return c;
}
}

The user to use ClassLoader.loadClass() It’s essentially using the parental delegation model

findClass(name) Combined findClass(name), findClass() It’s just an extension of parental delegation , You can expand the search path of the class by yourself

Four . Break the parental delegation mechanism

4.1 Class.forName()

As mentioned above ,class.forName() It’s called native Method , Don’t go with parental delegation code

4.2 With the help of Launcher Construction method and setContextClassLoader()

public class Launcher {

static class AppClassLoader extends URLClassLoader {
}
static class ExtClassLoader extends URLClassLoader {
}
public Launcher() {

try {

this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
}
// hold AppClassLoader Set to thread loader 
Thread.currentThread().setContextClassLoader(this.loader);
}
}

Launcher When instantiated, will AppClassLoader Set in the AppClassLoader ExtClassLoader In the thread context of

That is, after loading the core class , Before loading custom classes , The thread that loads the class , Can get AppClassLoader

setContextClassLoader(this.loader); stay SPI Breaking the parental delegation model plays a key role

发表回复