Java 类加载的一些理解

首先类加载过程的确是使用双亲委托方式,就是先找parent的classLoader加载,Java有几个固定的classLoader:1、BootstrapClassLoader 2、ExtClassLoader 3、AppClassLoader 这里有篇文章,也讲些了这些classLoader的关系 加载器。

但是网上很多文章说这几个加载器是有继承关系,然后我看到代码它们是没有继承关系的,但是它们都有个getParent()方法去获取所谓的父加载器,其实这个值的设置就要看Launcher的代码

public class Launcher {
 private static URLStreamHandlerFactory factory = new Factory();
 private static Launcher launcher = new Launcher();

public static Launcher getLauncher() {
  return launcher;
 }

private ClassLoader loader;

// ClassLoader.getSystemClassLoader会调用此方法
 public ClassLoader getClassLoader() {
  return loader;
 }

public Launcher() {
  // 1. 创建ExtClassLoader
  ClassLoader extcl;
  try {
   extcl = ExtClassLoader.getExtClassLoader();
  } catch (IOException e) {
   throw new InternalError("Could not create extension class loader");
  }

// 2. 用ExtClassLoader作为parent去创建AppClassLoader
  try {
   loader = AppClassLoader.getAppClassLoader(extcl);
  } catch (IOException e) {
   throw new InternalError("Could not create application class loader");
  }

// 3. 设置AppClassLoader为ContextClassLoader
  Thread.currentThread().setContextClassLoader(loader);
  // ...
 }

static class ExtClassLoader extends URLClassLoader {
  private File[] dirs;

public static ExtClassLoader getExtClassLoader() throws IOException {
   final File[] dirs = getExtDirs();
   return new ExtClassLoader(dirs);
  }

public ExtClassLoader(File[] dirs) throws IOException {
   super(getExtURLs(dirs), null, factory);
   this.dirs = dirs;
  }

private static File[] getExtDirs() {
   String s = System.getProperty("java.ext.dirs");
   File[] dirs;
   // ...
   return dirs;
  }
 }

/**
  * The class loader used for loading from java.class.path. runs in a
  * restricted security context.
  */
 static class AppClassLoader extends URLClassLoader {

public static ClassLoader getAppClassLoader(final ClassLoader extcl) throws IOException {
   final String s = System.getProperty("java.class.path");
   final File[] path = (s == null) ? new File[0] : getClassPath(s);

URL[] urls = (s == null) ? new URL[0] : pathToURLs(path);
   return new AppClassLoader(urls, extcl);
  }

AppClassLoader(URL[] urls, ClassLoader parent) {
   super(urls, parent, factory);
  }

/**
  * Override loadClass so we can checkPackageAccess.
  * 这个方法似乎没什么必要,因为super.loadClass(name, resolve)时也会checkPackageAccess
  */
  public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
   int i = name.lastIndexOf('.');
   if (i != -1) {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
     //
     sm.checkPackageAccess(name.substring(0, i));
    }
   }
   return (super.loadClass(name, resolve));
  }

}
}

1.Launcher源码里定义了static的扩展类加载器ExtClassLoader, static的系统类加载器AppClassLoader。

2.它们都是默认包级别的,它们都是继承URLClassLoader,这就意味着我们的代码里,不能定义ExtClassLoader laoder = ...或AppClassLoader loader = ...。我们只能ClassLoader loader = ...,而在实际运行时,我们应当能辨别这个loader到底是哪个具体类型。

3.在ExtClassLoader构造器里,并没有指定parent,或者说ExtClassLoader的parent为null。因为ExtClassLoader的parent是BootstrapLoader,而BootstrapLoader不存在于Java Api里,只存在于JVM里,我们是看不到的,所以请正确理解"ExtClassLoader的parent为null"的含义。

4.在AppClassLoader构造器里,有了parent。实例化AppClassLoader的时候,传入的parent就是一个ExtClassLoader实例。

5.看看Launcher的构造方法。

1.先实例化ExtClassLoader,从java.ext.dirs系统变量里获得URL[]。

2.用这个ExtClassLoader作为parent去实例化AppClassLoader,从java.class.path系统变量里获得URL[]。Launcher getClassLoader()就是返回的这个AppClassLoader。

3.设置AppClassLoader为ContextClassLoader。

到这里,关键是我们是怎么使用这个Launcher的,可以看看ClassLoader的代码,在构造函数中

protected ClassLoader() {
        this(checkCreateClassLoader(), getSystemClassLoader());
    }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/0f1b3fc2d9109fefd22c10b82f52f3f5.html