Comprensión profunda del mecanismo de delegación de padres

1. ¿Qué es el mecanismo de delegación de los padres?

Cuando un cargador de clases determinado necesita cargar un archivo .class, primero delega esta tarea a su cargador de clases superior. Esta operación es recursiva. Si el cargador de clases superior no lo carga, cargará la clase en sí.

Inserte la descripción de la imagen aquí

2. Cargador de clases
  • BootstrapClassLoader (cargador de clases de inicio)
    escrito en c ++, cargando la biblioteca principal de Java java. *, Construyendo ExtClassLoader y AppClassLoader. Dado que el cargador de clases de inicio involucra los detalles de implementación local de la máquina virtual, los desarrolladores no pueden obtener directamente una referencia al cargador de clases de inicio, por lo que no se permiten operaciones directas por referencia.

  • ExtClassLoader (cargador de clases extendido estándar)
    Escriba en java, cargue la biblioteca extendida, como jre en classpath, javax. * O java.ext.dir en la ubicación especificada, los desarrolladores pueden usar directamente el cargador de clases extendido estándar.

  • AppClassLoader (cargador de clases del sistema)
    escrito en java, el directorio donde se encuentra el cargador, como la clase donde se encuentra user.dir

  • CustomClassLoader (cargador de clases definido por el usuario)
    escrito en Java, cargador de clases definido por el usuario, puede cargar el archivo de clase de la ruta especificada

3. La ruta de carga del cargador de clases
import java.net.URL;
import java.net.URLClassLoader;
 
/*
分析BootstrapClassLoader/ExtClassLoader/AppClassLoader的加载路径
*
*/
public class ClassPath_of_Bootstrap_Ext_AppClassLoader {
 
    public static void main(String[] args) {
        System.out.println("BootstrapClassLoader 的加载路径: ");
        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        for (URL url : urls) {
            System.out.println(url);
        }
        System.out.println("----------------------------");
 
        //取得扩展类加载器
        URLClassLoader extClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader().getParent();
        System.out.println(extClassLoader);
        System.out.println("扩展类加载器 的加载路径: ");
        urls = extClassLoader.getURLs();
        for (URL url : urls) {
            System.out.println(url);
        }
        System.out.println("----------------------------");
 
 
        //取得应用(系统)类加载器
        URLClassLoader appClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        System.out.println(appClassLoader);
        System.out.println("应用(系统)类加载器 的加载路径: ");
        urls = appClassLoader.getURLs();
        for (URL url : urls) {
            System.out.println(url);
        }
        System.out.println("----------------------------");
    }
}

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

  • BootstrapClassLoader cargador de clases de inicio: carga la biblioteca central en el directorio jre /
  • Cargador de clase extendido ExtClassLoader: carga el paquete de extensión en el directorio / jre / lib / ext /
  • Cargador de clases de la aplicación AppClassLoader (sistema): carga el paquete en la ruta de la ruta de clases
4. Comprensión del código fuente
protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先检查这个classsh是否已经加载过了
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // c==null表示没有加载,如果有父类的加载器则让父类加载器加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        //如果父类的加载器为空 则说明递归到bootStrapClassloader了
                        //bootStrapClassloader比较特殊无法通过get获取
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {}
                if (c == null) {
                    //如果bootstrapClassLoader 仍然没有加载过,则递归回来,尝试自己去加载class
                    long t1 = System.nanoTime();
                    c = findClass(name);
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
1. Diagrama de flujo

Inserte la descripción de la imagen aquí

2. Proceso

Primero determine si la clase se ha cargado.
Si no está cargada, se pasa al cargador principal para cargarla,
si el cargador principal no puede cargarla, usa findClass () para cargarla por sí mismo. Por lo tanto, es un proceso recursivo ascendente.
Personalizado Al cargar el cargador, debe volver a escribir el método findClass porque está vacío y no tiene contenido:

5. La función del mecanismo de delegación de los padres
1. Garantizar la seguridad

Evite que el mismo .class se cargue repetidamente. Pregunte lo anterior confiando. Una vez cargado, no es necesario volver a cargarlo. Garantice la seguridad de los datos.

2. Garantizar la singularidad

Asegúrese de que el .class principal no se pueda alterar. A través del método de delegación, no se manipulará el .clas principal, incluso si se manipula, no se cargará, e incluso si se carga, no será el mismo objeto .class. Diferentes cargadores cargan el mismo .class y no el mismo objeto Class. Esto garantiza la seguridad de la ejecución de la clase.

Imagínense, si no hay un modelo de delegación padre pero cargado por cada cargador de clases, si el usuario escribe una clase java.lang.Object con el mismo nombre y la coloca en ClassPath, varios cargadores de clases cargarán esta clase en la memoria. habrá múltiples clases de Objeto diferentes en el sistema, por lo que el resultado de la comparación entre las clases y la unicidad de las clases no estará garantizado, porque los Objetos son todos diferentes, entonces el programa se ejecutará e iniciará errores, y también se asegurará de que la JVM puede ser una operación segura normal.

Supongo que te gusta

Origin blog.csdn.net/qq_43141726/article/details/114373312
Recomendado
Clasificación