base JVM - el cargador modelo de delegación de clase con los padres

I. Introducción

  Este es el JVMquinto en el blog de la serie, y es el último, terminar este blog, voy a la parada temporal JVMde aprendizaje, empecé a estudiar otros aspectos de la. Este blog sólo para hablar de JVMcargadores de clases, así como el modelo de delegación cargador de clases padre.


En segundo lugar, el texto

 2.1 ¿Cuál es el cargador de clases

  En primer lugar tenemos que saber una cosa, y eso es lo que es el cargador de clases? Todos sabemos que nuestras necesidades de código para ser compilados a classcódigo de bytes a ser ejecutado, JVMel intérprete sólo puede reconocer el código de bytes no se puede ejecutar Javael código fuente. Los procedimientos se realizan en la memoria, por lo que ser capaz de ejecutar código de bytes, que tendrá que ser leído en la memoria. El código de bytes se leen en la memoria de trabajo, un cargador de clases se lleva a cabo. El cargador de clases proporcionó nombre completo de clase (nombre de paquete + nombre de la clase), la clase a encontrar el camino correspondiente classarchivo que fue leído a JVMla zona método administrado, con el fin de ejecutar instrucciones de código en el mismo, la clase visitada datos. Sobre mecanismo de carga de clases, puede hacer referencia a este blog: la base JVM - clase de análisis de proceso de carga .

  Para el cargador de clases, es necesario prestar atención a un problema. Cada clase se determina con carácter único y un mismo cargador de clases. ¿Qué significa esto? Es decir, si el código de bytes de una clase, utilizando dos cargador de clases diferentes para cargar, para la JVM, la carga será identificado como estas dos dos clases diferentes . Por ejemplo, tenemos una clase Test, el cargador de clases crea una costumbre para cargarlo, y el cargador de clases personalizadas obtuvimos Classcrear objetos Testobjetos t(reflexión), funcionando en el momento t instanceof Test, obtenida será false. Debido a que este objetivo se consigue mediante una clase personalizada El cargador carga la Testcreación, y la intanceofdeclaración Testes una JVMclase cargada por Test, por JVM, esto es de dos clases diferentes. Además, para la clase tienen el mismo nombre completamente calificado del mismo cargador de clases va a cargar la carga sólo una vez, no se repite .


 2.2 Clasificación cargador de clases

  En Java, el cargador de clases se divide generalmente en cuatro categorías, a saber:

  • cargador de clases de arranque (en arranque cargador de clases);
  • cargador de clases de extensión (Extensión ClassLoader);
  • cargador de clases de aplicaciones (Aplicación ClassLoader);
  • cargador de clases personalizado (cargador de clases de usuario);

  He aquí un resumen de lo que cada uno de estos cuatro cargador de clases diferentes.


(1) Inicio de clases cargador (cargador de clases Bootstrap)

  Inicio cargador de clases no es el Javalenguaje de implementación, sino por la C++realización de la (máquina virtual HotSpot), que se encarga de cargar %JAVA_HOME%\libdirectorio de clases, por ejemplo String, Integer, HashMapque se colocan en esta categoría ....... directorio, por lo se carga por el cargador de clases de arranque. Además, JVMtambién proporciona un parámetro de configuración -Xbootclasspath, los archivos de clase (por ejemplo, bajo el directorio especificado por el jarpaquete, classarchivo) será cargado cargador de clases de arranque. Desde el cargador de clases se C++implementa, que no pertenece a la Javaparte, pero una parte de la máquina virtual, no puede Javadirectamente código de referencia. El código siguiente puede intentar obtener Stringla clase del cargador de clases, es decir, el cargador de clases de arranque, pero el resultado es la producción null, ya que no es Javauna parte de:

public static void main(String[] args) {
    ClassLoader c = String.class.getClassLoader();
    System.out.println(c);  // 输出null
}


(2) cargador de clases extendida (Extensión ClassLoader)

  Se cargador de clases de extensión Javaimplementado, es la clase de implementación sun.misc.Launcher$ExtClassLoader(el nombre puede verse que esta es una clase interna), este cargador de clases es responsable de cargar %JAVA_HOME%\lib\extel directorio de la clase. Dado que este es un cargador de clases Java, se puede implementar directamente en el Javaprograma de referencia. Se puede establecer un %JAVA_HOME%\lib\exttipo de directorio de Classobjetos para conseguir el cargador de clases, esto se puede obtener mediante el siguiente método (un modelo de delegación matriz con sede método, explicado más adelante):

public static void main(String[] args) {
    // 获得自己写的类的加载器
    ClassLoader c = Main.class.getClassLoader();
    // Main加载器的父加载器就是扩展类加载器
    ClassLoader c2 = c.getParent();
    // 输出:sun.misc.Launcher$ExtClassLoader@eed1f14
    System.out.println(c2);
}


(3) cargador de clases de la aplicación (Aplicación ClassLoader)

  Este tipo de carga es el Javalenguaje de implementación, la clase de aplicación es sun.misc.Launcher$AppClassLoaderde $se puede ver ese símbolo, que es una clase interna. Es responsable de cargar la ruta de clase ( CLASSPATH) en la biblioteca, y nuestro código también pertenecen (en el camino CLASSPATHde la ruta actual si se incluye). Por lo tanto, cuando escribimos su propio Javacódigo no especifica el cargador de clases, este cargador se utiliza para cargar por defecto. Desde el cargador de clases se Javaimplementa, puede ser referenciado en nuestro código, referencia de la siguiente manera:

public static void main(String[] args) {
    // 方式1:使用自定义类的Class对象获得
    ClassLoader c1 = Main.class.getClassLoader();
    // 方式2:使用ClassLoader类的getSystemClassLoader方法获得
    ClassLoader c2 = ClassLoader.getSystemClassLoader();

    // 输出:sun.misc.Launcher$AppClassLoader@18b4aac2
    System.out.println(c1);
    // 输出:true
    System.out.println(c1 == c2);
}


(4) un cargador de clases personalizadas (cargador de clases de usuario)

  Si es necesario, se puede escribir su propio cargador de clases, y he escrito cargador de clases que se llama un cargador personalizado. Escribir el cargador de clases personalizado es muy simple: heredada ClassLoaderclase, entonces anulan estos métodos pueden ser. Para la Javarealización del cargador de clases, que se invoca loadClass()el método de carga de clases, por lo que podemos reemplazar este método, pero no se recomienda esta práctica, ya que es fácil de destruir el mecanismo de carga de clases (después de que los padres serán referidos al delegado modelo). Lo más recomendable es reemplazar el findClass()método que va a loadClass()ser llamado en. En el findClass()método, la lectura a cargar la clase classde archivo, se convierte en una matriz de bytes, y luego llamar a la clase principal defineClassmétodo para convertir una matriz de bytes Classobjeto se devuelve, como se muestra a continuación:

// 自定义类加载器,实现ClassLoader
class MyClassLoader extends ClassLoader {

    //指定class文件的路径路径
    private String path;
    public MyClassLoader(String classPath) {
        path = classPath;
    }

    /**
     * 重写findClass方法
     * @param name 是我们这个类的全路径
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class log = null;
        // 获取该class文件字节码数组
        byte[] classData = getData();

        if (classData == null) {
            throw new ClassNotFoundException("Class Not Found");
        }
        // 将class的字节码数组转换成Class类的实例,并返回
        return defineClass(name, classData, 0, classData.length);;
    }

    /**
     * 读取class,将字节码转换成字节数组
     * @return
     */
    private byte[] getData() {
        // 省略读取的代码
        // 普通IO读取即可
    }
}


 2.3 modelo de delegación de los padres

  Relación entre la anterior correspondiente al modelo de delegación imagen se llama el cargador de clases padre. Para cada cargador de clases, cargador tiene un padre (excepto el cargador de clases de arranque). Cuando el cargador de clases para cargar una clase, será el primer delegado a su cargador de clases padre a la carga, si el padre también tiene un cargador cargador de padres, siguen encargado hasta el cargador de clases de arranque. Inicio intentos cargador de clases para cargar esta clase, si la clase en su propio directorio bajo gestión, y aún no se ha cargado, cargado con éxito, o dejado de carga; si no se pudo cargar, y luego al cargador de clases de extensión inferior a la carga, el cargador de clases de extensión realiza la misma operación. En general, el modelo de delegación de los padres es la primera clase a los padres intentos cargador de clases a la carga, si falla la carga, entonces se va a cargar por las subclases, cada capa es tan . En la implementación real, esta relación entre padres e hijos no se logra por la herencia, sino por la combinación lograda en ClassLoaderclase, hay una propiedad llamada parent, es un puntero a sus referencias cargador padre (antes del código de cargador de clases de extensión se obtiene de esta manera).

  Aquí estamos ClassLoadertipo de loadClasscódigo fuente método, mirada en el código de implementación de modelo de delegación principal específico:

// name为类的全限定类名
public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}

// 这个重载方法被上面的方法调用
protected Class<?> loadClass(String name, boolean resolve) 
    throws ClassNotFoundException {
    
    // 对以下代码进行多线程同步
    synchronized (getClassLoadingLock(name)) {
        // 首先,判断这个类是否已经被加载
        Class<?> c = findLoadedClass(name);

        // c为null表示还没有被加载,则进行加载
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                // 此处是双亲委托机制的关键
                // 如果当前加载器有父加载器
                if (parent != null) {
                    // 调用父加载器的loadClass对类进行加载
                    c = parent.loadClass(name, false);
                } else {
                    // 若没有父类加载器,则调用引导类加载器尝试加载
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // 此时加载失败将抛出异常,提示类找不到
                // 不需要处理,继续执行
            }

            // c为null表示调用上层类加载器加载失败
            if (c == null) {
                long t1 = System.nanoTime();
                // 调用当前类加载器的findClass进行加载
                // 所以自定义类加载器推荐重写findClass方法
                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;
    }
}

  Por el código anterior, podemos ver claramente cómo se implementa el mecanismo de los padres delegado. Que este mecanismo de qué sirve? Uso de padres delegación mecanismo asegura que la clase se carga condición satisface un primer cargador de clases. Para un cargador de clases para cada clase sólo será cargado una vez, por lo que la carga no hará que la misma clase varias veces, una situación para ser cargado o una clase de cargador de clases diferentes. Dicho antes, la única clase se determina por su propia y su cargador de clases a la carga, el modelo de delegación utilizando la clase de los padres es bueno para evitar la carga de una pluralidad de cargadores, el mismo no da como resultado equivalente en memoria clase. Por ejemplo, se define una java.lang.Stringclase, si no hay un modelo de delegación de los padres, dos se produjeron en la memoria String, pero en nuestra opinión, no sólo uno, en este momento hará que el programa para generar un inexplicable error. El modelo de delegación de los padres para asegurar que la clase del mismo nombre de esta manera no se carga a plazo, por lo que nuestra propia definición de la clase nunca será capaz de utilizar el mismo nombre, aunque el compilador puede (donde se puede probar su propia).

  Por supuesto, los padres no se delegan modelo de JVMespecificación de mandato, sino una estrategia recomendada. Así que no podemos seguir este modelo al escribir su propio cargador de clases, tales como la reescritura loadClassmétodo cubiertos por este mecanismo. Pero si no es necesario, o no se recomienda.


En tercer lugar, el resumen

  Y los padres sobre el cargador modelo de delegación de clase querrían decirlo. Las dos partes de la cara hizo una descripción bastante detallada, creo que sería después de leer Javaalgunas de las características relevantes son más comprensión en profundidad, por lo general podemos resolver algunas dudas.


En cuarto lugar, la referencia

  • "La comprensión en profundidad de la Máquina Virtual de Java"

Supongo que te gusta

Origin www.cnblogs.com/tuyang1129/p/12515069.html
Recomendado
Clasificación