Java---类加载器(ClassLoader)

387 阅读4分钟

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

类加载器

classloader的加载过程

classloader1.jpeg 类从被加载到虚拟机内存到被卸载,整个完整的生命周期包括:类加载、校验、准备、解析、初始化、使用和卸载七个阶段。其中验证,准备,解析三个部分统称为连接。接下来我们可以详细了解下类加载的各个过程。

加载:把class字节码文件从各个来源通过类加载器加载到内存中

校验:保证加载进来的字节流符合虚拟机规范

准备:为类变量分配内存,并赋予初始值

解析:将常量池的符号引用替换为直接引用过程

初始化:对类变量初始化,执行类构造器的过程

双亲委托机制

ClassLoader的双亲委派模型中,各个ClassLoader之间的关系是通过组合关系来复用父加载器。当一个ClassLoader收到来类加载的请求,首先把该请求委派该父类ClassLoader处理,当父类ClassLoader无法处理时,才由当前类ClassLoader来处理。对于每个ClassLoader这个方式,也就是父类的优先于子类处理类加载的请求,那么也就是说任何一个请求第一次处理的便是最顶层的Bootstrap ClassLoader(启动类加载器)。

类加载器的层级查找顺序依次为:启动类加载器,扩展类加载器,系统类加载器。系统类加载器是默认的应用程序类加载器。

classloader2.jpg

Bootstrap ClassLoader

启动类加载器,一般由C++实现,是虚拟机的一部分。该类加载器主要职责是将JAVA_HOME路径下的\lib目录中能被虚拟机识别的类库(比如rt.jar)加载到虚拟机内存中。Java程序无法直接引用该类加载器

Extension ClassLoader

扩展类加载器,由Java实现,独立于虚拟机的外部。该类加载器主要职责将JAVA_HOME路径下的\lib\ext目录中的所有类库,开发者可直接使用扩展类加载器。 该加载器是由sun.misc.Launcher$ExtClassLoader实现。

Application ClassLoader

应用程序类加载器,该加载器是由sun.misc.Launcher$AppClassLoader实现,该类加载器负责加载用户类路径上所指定的类库。开发者可通过ClassLoader.getSystemClassLoader()方法直接获取,故又称为系统类加载器。当应用程序没有自定义类加载器时,默认采用该类加载器

自定义 ClassLoader

每一个ClassLoader都拥有自己独立的类名称空间,类是由ClassLoader将其加载到Java虚拟机中,故类是由加载它的ClassLoader和该类本身一起确定其在Java 运行时环境的唯一性。故只有同一个ClassLoader加载的同一个类,才能算是Java 运行时环境中的相同的两个类。哪怕是来自同一个Class文件,即使被同一个虚拟机加载的两个类,只要ClassLoader不同,那么也属于不同的类。对于equals()、isinstanceof()等方法来判断对象的相等或所属关系都是需要基于同一个ClassLoader。

双亲委派机制的好处:

保证java核心库的安全性(例如:如果用户自己写了一个java.lang.String类就会因为双亲委派机制不能被加载,不会破坏原生的String类的加载)

主要源码

protected Class<?> loadClass(String name, boolean resolve)
 throws ClassNotFoundException
{
 synchronized (getClassLoadingLock(name)) {
 //检查当前的class对象是否被加载过,被加载过就返回
 Class<?> c = findLoadedClass(name);
 if (c == null) {
 long t0 = System.nanoTime();
 try {
  //判断当前的classLoader是否有父类
  //若存在父类
  if (parent != null) {
  //调用父类的loadClass
  c = parent.loadClass(name, false);
  } else {//不存在父类,表示当前的classLoader是extClassLoader
  //那么就会调用启动类判断是否加载过
  c = findBootstrapClassOrNull(name);
  }
  } catch (ClassNotFoundException e) {
  // ClassNotFoundException thrown if class not found
  // from the non‐null parent class loader
  }
  //到目标位置,app ext boot都没有去加载过
  if (c == null) {
  // If still not found, then invoke findClass in order
  // to find the class.
  long t1 = System.nanoTime();
  //委托我们的子类的classLoader去找
  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) {
   //对类进行link操作
  resolveClass(c);
  }
  return c;
  }
 }

\