Prefacio
Todos deben saber que cuando se inicia un proyecto Java, el JVM encontrará el método principal y cargará el archivo de clase y el archivo de clase en el paquete JAR referenciado de acuerdo con las llamadas entre los objetos (los pasos se dividen en carga, verificación, preparación, análisis, inicialización, uso y descarga). El área del método abre la memoria para almacenar la estructura de datos de tiempo de ejecución de la clase (incluidas las variables estáticas, los métodos estáticos, las piscinas constantes, las estructuras de clase, etc.), y al mismo tiempo, el objeto de clase correspondiente se genera en el montón para apuntar a la estructura de datos de tiempo de ejecución de clase correspondiente en el área de método.
Para resumir en la oración más simple, el proceso de carga de clase es que el JVM lee el archivo de código de bytecodo de clase a través de las secuencias de IO en función de la ruta del archivo de clase requerido, y lo inyecta en la memoria a través de una serie de pasos de análisis e inicialización. Los cargadores de clase en Java incluyen: BootstrapClassLoader (capa superior), ExtClassLoader, AppClassLoader y ClassLoader definido por el usuario (capa inferior). Para diferentes tipos de paquetes JAR (o archivos de clase), JVM tendrá diferentes tipos de cargadores de clase para cargar.
La relación correspondiente es la siguiente:
BootstraPClassLoader se usa para cargar las clases requeridas para JVM en ejecución:
Java_home/jre/lib/recursos.jar: java_home/jre/lib/rt.jar: java_home/jre/lib/sunrasign.jar: java_home/jre/lib/jsse.jar: java_home/jre/lib/jCe.jar: java_home/jre/libets.Jar Java_home/jre/lib/jfr.jar: java_home/jre/lib/classes
ExtClassLoader se usa para cargar clases de extensión:
../Java/extensions: ../java_home/jre/lib/ext: ../library/java/extensions:/network/library/java/extensions: ../system/library/java/extensions: ../lib/java
AppClassLoader se usa para cargar las clases creadas en classPath y clases a las que se hace referencia en el paquete JAR en nuestro proyecto.
Toda la carga de clase se carga a través de un mecanismo llamado delegación principal.
Por ejemplo, la clase está cargada por el cargador de nivel más bajo (cargador de clases definido por el usuario). Este cargador primero llamará al cargador de nivel anterior (AppClassLoader) para que se cargue, y el AppClassLoader continuará entregándose al nivel superior (ExtClassLoader) para cargar hasta el BootstraPClassLoader. Si el classpath cargado por BootstraPClassLoader no puede encontrar esta clase, se entregará al cargador (ExtClassLoader) de la siguiente capa para cargar. Si no se puede encontrar esta clase, se continuará entregándose a la siguiente capa (AppClassLoader) para la carga. Y así sucesivamente, si el cargador de clases definido por el usuario no puede encontrar esta clase, el programa lanzará un ClassNotFoundError.
Todo el proceso de carga se muestra de la siguiente manera:
(La imagen se cita de: https://www.cnblogs.com/xing901022/p/4574961.html)
El seguimiento del código fuente de la fuente de carga de clase es el siguiente (el código fuente se ha simplificado adecuadamente aquí). Los lectores pueden hacer clic en el código fuente para ver:
paquete java.lang.classloader; import ...... clase protegida <?> LoadClass (name de cadena, resolve boolean) lanza ClassNotFoundException {Synchronized (getClassLoadingLock (name)) {// Primero, encuentre en la memoria de la máquina virtual si esta clase se ha cargado ... ¡el problema principal con la clase Cache está! ! ! Clase <?> C = findloadedClass (nombre); if (c == null) {long t0 = system.nanotime (); Pruebe {if (parent! = null) {// deje que el cargador de capa anterior se cargue primero c = parent.loadclass (nombre, falso); } else {c = findBootstrapClassOnnull (nombre); }} Catch (ClassNotFoundException e) {// classnotFoundException lanzado si la clase no se encuentra // desde el cargador de clase principal no nulo} if (c == null) {// calendario el método findclass implementado por este cargador para cargar c = findclass (nombre); }} if (resolve) {resolveclass (c); } return c; }}Puede apreciar completamente el proceso de mecanismo de delegación matriz en el código fuente, y las tres oraciones de código más importantes han sido marcadas:
Si el usuario necesita un cargador personalizado y cargue el archivo de clase de la ruta especificada, necesita heredar el cargador de clases e implementar el método FindClass (nombre de cadena). Como ejemplo:
paquete com.linuxidc.utils; import java.io.bytearrayoutputStream; import java.io.fileInputStream; import java.io.ioException; import java.io.inputstream; clase pública ServiceClassLoader extiende la clase de clases {classpath privado; public ServiceClassLoader (String classpath) {this.classpath = classpath; } /*** Reescribe el método FindClass de la clase principal. La Clase de carga de la clase principal llamará a este método */ @Override la clase protegida <?> FindClass (name de cadena) lanza ClassNotFoundException {class <?> C = NULL; byte [] classData = getClassData (nombre); if (classData! = NULL) {c = definidoClass (name, classData, 0, classData.length); } else {lanzar new ClassNotFoundException (); } return c; } // Lea el archivo de clase a través de la transmisión IO y conviértalo en una matriz de byte privado byte [] getClassData (name de cadena) {string path = classpath + "/" + name.replace ('.', '/') + ".Class"; InputStream istream = null; ByteArRayOutputStream byteArRAyOutputStream = new ByteArRaReOutputStream (); intente {istream = new FileInputStream (ruta); byte [] buffer = new Byte [1024]; int temp = 0; while ((temp = istream.read (buffer))! =-1) {bytearRayOutputStream.write (buffer, 0, temp); } if (byteArRaReOutputStream! = NULL) {return byteArRaRyOutputStream.tobyTearray (); }} catch (Exception e) {E.PrintStackTrace (); } finalmente {try {if (istream! = null) {istream.close (); }} catch (ioException e) {E.PrintStackTrace (); } try {if (bytearRayOutputStream! = NULL) {byteArRaReOutputStream.close (); }} catch (ioException e) {E.PrintStackTrace (); }} return null; }}El código para usar el cargador de clases es el siguiente:
ServiceClassLoader ServiceClassLoader = new ServiceClassLoader ("c:/myclass"); czlass <?> C = serviceClassLoader.loadClass ("com.linuxidc.service.myclass");Si usa el mismo objeto ServiceClassLoader para cargar el mismo archivo de clase varias veces, ¡el objeto de clase después de cada carga es el mismo! Sin embargo, si el nuevo cargador de clases personalizado diferente carga el mismo archivo de clase, se devolverá un objeto de clase diferente cada vez.
Nota: El archivo de clase que desea cargar no se puede colocar en el directorio ClassPath y en cualquier subdirectorios, de lo contrario, el AppClassLoader lo cargará primero (esto se debe a que la carga de clase adopta el mecanismo de delegación matriz, y el AppClassLoader puede cargar todos los archivos de clase en ClassPath). Cada vez, se carga el mismo AppClassLoader, por lo que habrá problemas de almacenamiento en caché de clase.
Esto resuelve el problema de usar directamente la reflexión cuando se carga la clase JVM.
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.