Hablando de la primera parte del proceso de carga de clases.

1. Inicialización de carga de clases

  1. Cargando

    Cargue un archivo de clase en la memoria

  2. Enlace

    1. Verificación

      Verifique que el carácter del archivo de clase no cumpla con el estándar del archivo de clase

    2. Preparación

      Asignar valores predeterminados a las variables estáticas static int count = 10;

      En este paso cuenta = 0 valor predeterminado

    3. Resolución

      Las referencias de símbolos se convierten en direcciones de memoria a las que se puede acceder directamente

  3. Inicializando

    Asignación de variable estática al valor inicial

    Hablando de la primera parte del proceso de carga de clases.

2. Cargador de clases

1. JVM se carga dinámicamente bajo demanda y adopta un mecanismo de delegación principal

Use getClassLoader para obtener el cargador de clases. Si es Null, entonces es el cargador de clases BootStrap porque está implementado en C ++ y no hay una clase correspondiente.

Las clases que generalmente escribimos están bajo la ruta de clases, por lo que el cargador de clases de la aplicación las carga

Nota: Estos cuatro cargadores de clases no tienen una relación de herencia, sino una relación secuencial.

El cargador principal no es la clase principal, solo dice que no se puede cargar por sí mismo, por lo que se entrega al nivel superior para cargar

No son una relación de herencia, ¿cómo se pusieron en contacto? Usa una combinación ~~

Hablando de la primera parte del proceso de carga de clases.

2. ¿El diagrama del Paso 1 no ilustra la asignación de los padres? Te daré una foto para que entiendas la tarea de los padres.

¡No! ¿Por qué debería usar imágenes? Permítanme describir en una oración: classLoader encuentra en su propia caché si la clase XX se ha cargado, si no, encuentra su cargador de clases padre, y el cargador de clases padre encuentra en su propia caché si ya se ha cargado la Clase XX, si se encuentra , regrese, si no se encuentra, luego busque el cargador de clases principal, hasta BootStrap, si no se encuentra en el caché, luego mire hacia atrás desde el cargador de clases principal, el cargador principal le pide a su hijo que vea de qué usted es responsable. tal clase en el paquete jar? Si la hay, puede cargarla en la memoria. Si no, puede mirar el cargador de clases de su hijo. Verifíquelo todo el tiempo, y vea si el cargador de clases más pequeño se devuelve al final , o si no lo encuentra, lance una excepción. ClassNotFoundException

Todavía sucumbí a la imagen de arriba.

Hablando de la primera parte del proceso de carga de clases.

/**
 * @author 木子的昼夜
 */
public class MyClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException {
        MyClassLoaderTest.class.getClassLoader().loadClass("classtest.MyClassLoaderTest");
    }
}

// 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)) {
         // 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 order
                 // 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;
     }
 }

Patrón de diseño: método de plantilla de función de gancho

3. ¿Cómo es cuando se carga un archivo de clase en la memoria?

Hablando de la primera parte del proceso de carga de clases.

4. GetClassLoader () que quiere saber qué cargador de clases está cargado en la memoria por una determinada clase

System.out.println(String.class.getClassLoader());
// null --> BootStrap类加载器
System.out.println(sun.awt.HKSCS.class.getClassLoader());
// null --> BootStrap类加载器
       System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
// sun.misc.Launcher$ExtClassLoader@1d44bcfa --> Ext
System.out.println(ClassLoaderTest.class.getClassLoader());
// sun.misc.Launcher$AppClassLoader@18b4aac2--> App

5. ¿Por qué los padres delegan

  1. Por seguridad, si no hay una delegación principal, busque la clase directamente desde el cargador de clases personalizado (el problema principal)

    Hablando de la primera parte del proceso de carga de clases.

(1) Si personalizo un java.lang.String aquí,
escribo un script de minería en la clase String

(2) ¡Entonces Xiaoyueyue descargó mi biblioteca para usarla!

Él usó String, pensó que era una clase jdk, pero predije su predicción. Esta clase String ya es mía y controlada por mí.

(3) La delegación de los padres puede evitar este problema, porque el sistema siempre irá a la capa superior para ver si existe esta clase porque la capa superior la tiene, por lo que no usará la clase String que definí.

  1. Si la capa principal está cargada, no tengo que cargarla y luego cargar es un desperdicio de recursos (problema secundario)

6. Ahora que lo ha personalizado, ¿no es solo lo que dije?

¡No! El cargador de clases ya está restringido

7. Un ejemplo de relación padre-hijo del cargador de clases no es herencia sino composición

Al observar el código a continuación, los lectores pueden volver a intentarlo y probar con cuidado esta oración: El cargador de clases que carga el cargador de clases no es el cargador de clases padre del cargador de clases

System.out.println(ParentDemo.class.getClassLoader());
System.out.println(ParentDemo.class.getClassLoader().getClass().getClassLoader());
System.out.println(ParentDemo.class.getClassLoader().getParent());
System.out.println(ParentDemo.class.getClassLoader().getParent().getParent());

输出结果:
sun.misc.Launcher$AppClassLoader@18b4aac2
null
sun.misc.Launcher$ExtClassLoader@6e0be858
null

8. El alcance de cada cargador de clases

Puede echar un vistazo al código fuente de sun.misc.Launcher

  • BootstrapClassLoader: sun.boot.class.path
  • ExtensionClassLoader: java.ext.dirs
  • AppClassLoader: java.class.path
 public static void main(String[] args) {
     System.out.println("---------BOOT-----------------------");
     String boot = System.getProperty("sun.boot.class.path");
     Arrays.stream(boot.split(";")).forEach(s-> System.out.println(s));
     System.out.println("--------------Ext-------------------");
     String ext = System.getProperty("java.ext.dirs");
     Arrays.stream(ext.split(";")).forEach(s-> System.out.println(s));
     System.out.println("----------APP-----------------------");
     String app = System.getProperty("java.class.path");
     Arrays.stream(app.split(";")).forEach(s-> System.out.println(s));
}

输出结果:
---------BOOT-----------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\sunrsasign.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_144\jre\classes
--------------Ext-------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext
C:\WINDOWS\Sun\Java\lib\ext
----------APP-----------------------
C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\deploy.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\access-bridge-64.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\cldrdata.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\dnsns.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jaccess.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jfxrt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\localedata.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\nashorn.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunec.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunjce_provider.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunmscapi.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunpkcs11.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\zipfs.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\javaws.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfxswt.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\management-agent.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\plugin.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar
E:\workspace_idea\blogmaven\target\classes 
// 读者注意看这一个  这个是当前项目class文件地址

9. Cargador de clases personalizado

  1. Primero defina una clase Java cargada Test.java

    public class Test {
       public void say(){
           System.out.println("成功喽!");
       }
    }
  2. Compile Test.java en el directorio especificado

    javac  -encoding utf-8  -d E:/classes  Test.java 
  3. Heredar ClassLoader, anular el método de plantilla findClass, llamar a defineClass

    /**
    * @author 木子的昼夜
    */
    public class MyClassLoader extends ClassLoader  {
       @Override
       protected Class<?> findClass(String name) throws ClassNotFoundException {
           FileInputStream inputStream = null;
           ByteArrayOutputStream out = null;
           try {
               // 类名  aa.xx 转换为 aa/xx.class
               File file = new File("E:\\classes\\",name.replaceAll("\\.","/").concat(".class"));
               // 获取输入流
                inputStream = new FileInputStream(file);
               // 输出字节流
                out = new ByteArrayOutputStream();
    
               // 转换为字节数组
               int available = inputStream.available();
               byte[] byteArr = new byte[available];
               inputStream.read(byteArr);
    
            // 生成class 
               return defineClass(name,byteArr,0,byteArr.length);
           }catch (Exception e) {
               throw  new ClassNotFoundException();
           }finally {
               // 关闭流
               if (inputStream != null) {
                   try {
                       inputStream.close();
                   } catch (IOException e) {
                       e.printStackTrace();
                   }
               }
               if (out != null) {
                   try {
                       out.close();
                   } catch (IOException e) {
                       e.printStackTrace();
    
                   }
               }
           }
       }
    }
  4. prueba

    public static void main(String[] args) {
           try {
               Class<?> clazz = new MyClassLoader().loadClass("Test");
               // 获取声明的方法
               Method say = clazz.getDeclaredMethod("say");
               // 创建实例
               Object instance = clazz.newInstance();
               // 调用方法
               say.invoke(instance);
           }catch (Exception e) {
               e.printStackTrace();
           }
    }
    输出结果:
       成功喽!
  5. El cargador de clases personalizado carga clases autocifradas

    1. El archivo es suyo, puede cifrarlo mediante algún algoritmo después de que se complete la compilación,
      y cuando lo cargue con un ClassLoader personalizado, puede descifrarlo usted mismo
    2. Puede prevenir la descompilación
    3. Puede evitar la manipulación

10. Compilación híbrida

  1. Intérprete: intérprete de código de bytes

  2. JIT: compilador Just In - Time

        1.  -Xmixed 默认为混合模式 
      开始使用解释执行 启动速度快
      对热点代码进行实时检测和编译
        2.  -Xint 使用解释模式 启动快 执行慢
        3.  -Xcomp 使用纯编译模式 启动慢 运行快 
  3. Modo mezclado

    1. Intérprete + compilación hot code

    2. Interprete

    3. La detección de código activo detecta el uso de la compilación de código activo

      1.  多次被调用的方法(方法计数器:监测方法执行频率)
          2.  多次被调用的循环(循环计数器:监测循环执行频率)

Continuará...

Hay muchas imágenes en este artículo. Si no está seguro, puede prestar atención a la cuenta pública: Muzi Day and Night

Envíe "Class Load" para obtener la dirección de acceso de la imagen HD

Envíe "ruta" para obtener el esquema de esta serie de artículos

También puedes enviarme las preguntas que quieras hacerme, te responderé en cuanto la vea

Finalmente, adjunté mi cuenta pública y comencé a escribir un deseo y a progresar juntos:

Hablando de la primera parte del proceso de carga de clases.

Nota : El texto anterior solo representa opiniones personales y es solo para referencia. Si tiene alguna pregunta, por favor señale y salga de la cama inmediatamente y haga las correcciones.

Supongo que te gusta

Origin blog.51cto.com/12198094/2655976
Recomendado
Clasificación