Directorio de artículos
1. Implementación de código fuente del cargador de clases
El mecanismo de carga de clases de Java y la creación de instancias de objetos han aclarado los tipos de cargadores de clases en Java. En pocas palabras, Java viene con tres cargadores de clases. Sus funciones específicas sonCargue dinámicamente el archivo de clase en la máquina virtual JVM según sea necesario. Las implementaciones correspondientes de estos tres cargadores de clases son las siguientes:
- Cargador de clases de arranque, clase de
Bootstrap ClassLoader
atributo del sistema de cargasun.boot.class.path
en la ruta especificada, está escrito por C / C ++, es parte de una máquina virtual, lo que no se puede lograr en el código java conocido- Extienda el cargador de clases,
Extension ClassLoader
carguejava.ext.dirs
la clase en la ruta especificada por la propiedad del sistema , la clase de implementación essun.misc.Launcher.ExtClassLoader
- Cargador de clases de aplicación,
Application ClassLoader
cargando la variable de entornoClassPath
en la biblioteca, la propiedad del sistema esjava.class.path
una ruta especificada, para la clase de implementaciónsun.misc.Launcher.AppClassLoader
1.1 Cargador de clases abstracto Cargador de clases
java.lang.ClassLoader
Es una abstracción del cargador de clases a nivel de Java. Esta clase regula el proceso básico de carga de clases. Las propiedades y métodos más importantes son los siguientes:
parent
: Una referencia al cargador de clases principal. Un cargador de clases generalmente guarda una referencia al cargador de clases principal para implementar el mecanismo de delegación principal.loadClass()
Método, este método es el método principal del cargador de clases, que implementa la lógica de la delegación principal
public abstract class ClassLoader {
// The parent class loader for delegation
// Note: VM hardcoded the offset of this field, thus all new fields
// must be added *after* it.
private final ClassLoader parent;
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;
}
}
1.2 ExtClassLoader
sun.misc.Launcher.ExtClassLoader
Es la clase de implementación del cargador de clases extendido. Los métodos más importantes de esta clase son los siguientes:
getExtDirs()
El método especifica lajava.ext.dirs
clase bajo la ruta especificada por su propiedad del sistema de carga- Su método de construcción con parámetros llama al método de construcción de la clase principal, y el parámetro del cargador de clases principal pasado se especifica explícitamente como nulo, es decir, el cargador de clases extendido no tiene un cargador de clases principal de nivel Java.
static class ExtClassLoader extends URLClassLoader {
private static volatile Launcher.ExtClassLoader instance;
public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
if (instance == null) {
Class var0 = Launcher.ExtClassLoader.class;
synchronized(Launcher.ExtClassLoader.class) {
if (instance == null) {
instance = createExtClassLoader();
}
}
}
return instance;
}
private static Launcher.ExtClassLoader createExtClassLoader() throws IOException {
try {
return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
public Launcher.ExtClassLoader run() throws IOException {
File[] var1 = Launcher.ExtClassLoader.getExtDirs();
int var2 = var1.length;
for(int var3 = 0; var3 < var2; ++var3) {
MetaIndex.registerDirectory(var1[var3]);
}
return new Launcher.ExtClassLoader(var1);
}
});
} catch (PrivilegedActionException var1) {
throw (IOException)var1.getException();
}
}
void addExtURL(URL var1) {
super.addURL(var1);
}
public ExtClassLoader(File[] var1) throws IOException {
super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
}
private static File[] getExtDirs() {
String var0 = System.getProperty("java.ext.dirs");
File[] var1;
if (var0 != null) {
StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
int var3 = var2.countTokens();
var1 = new File[var3];
for(int var4 = 0; var4 < var3; ++var4) {
var1[var4] = new File(var2.nextToken());
}
} else {
var1 = new File[0];
}
return var1;
}
......
}
1.3 Cargador de clases de aplicaciones AppClassLoader
El cargador de clases de aplicaciones también se llamaCargador de clases de sistema, sun.misc.Launcher.AppClassLoader
Es su clase de implementación, los métodos más importantes de esta clase son los siguientes:
getAppClassLoader()
El método especifica lajava.class.path
clase bajo la ruta especificada por su propiedad del sistema de carga- Reescriba la
loadClass()
forma de hacer una carga optimizada de archivos de clase, si una clase existe en el directorio de la caché pero no en la memoria, si se lleva a cabo directamente连接
o si necesita un cargador de clases principal para cargar
static class AppClassLoader extends URLClassLoader {
final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
final String var1 = System.getProperty("java.class.path");
final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
public Launcher.AppClassLoader run() {
URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
return new Launcher.AppClassLoader(var1x, var0);
}
});
}
AppClassLoader(URL[] var1, ClassLoader var2) {
super(var1, var2, Launcher.factory);
this.ucp.initLookupCache(this);
}
public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
int var3 = var1.lastIndexOf(46);
if (var3 != -1) {
SecurityManager var4 = System.getSecurityManager();
if (var4 != null) {
var4.checkPackageAccess(var1.substring(0, var3));
}
}
if (this.ucp.knownToNotExist(var1)) {
Class var5 = this.findLoadedClass(var1);
if (var5 != null) {
if (var2) {
this.resolveClass(var5);
}
return var5;
} else {
throw new ClassNotFoundException(var1);
}
} else {
return super.loadClass(var1, var2);
}
}
......
}
2. La realización del mecanismo de delegación de padres
La figura es un posible proceso de carga de clases, muchos pasos importantes en el proceso es native
el método a lograr, no se pueden conocer los detalles de la capa de Java. El código del método principal de la clase de carga de la capa Java es el siguiente. En una breve descripción, incluye principalmente los siguientes pasos:
- Un
AppClassLoader
momento para cargar la clase, primero vea si la clase se ha cargado antes, si se ha adquirido de la caché o si necesita delegar al cargador de clases principal para manejarExtClassLoader
Procesos yAppClassLoader
totalmente coherentes, si no se había cargado la clase de destino,Bootstrap ClassLoader
para realizar la carga lógica que estásun.mic.boot.class
configurada se carga la ruta a la clase de destino, devuelve cargada, sin carga para que el niño encuentre su propio cargadorBootstrap ClassLoader
Si no se carga correctamente en la clase de destino, encontrará la clase de destino para cargarExtClassLoader
en lajava.ext.dirs
ruta configurada, regresará si tiene éxito y luego dejará que el subcargador cargue la clase si fallaExtClassLoader
La clase de carga no tuvo éxito,AppClassLoader
lajava.class.path
clase de destino de búsqueda de la configuración de la ruta, la carga regresó para encontrarla. Si no lo encuentra, deje que el cargador de subclase lo encuentre, si no hay subclase, se lanzarán varias excepciones
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); // 1.首先判断类是否已经被加载
if (c == null) {
// 2. 未被加载则进行双亲委派加载
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) {
//3.父类加载器 loadClass 未加载到类才调用 findClass
// 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;
}
}