类加载器

  1. 类加载分类:

    1. 启动类加载器(BootstrapClassLoader):最顶层的加载类,由C++实现,负责加载<JAVA_HOME>\lib目录下以及被-Xbootclasspath参数所指定的路径中存放的,并且能够被Java虚拟机识别的类(jar等等)。
    2. 扩展类加载器(ExtensionClassLoader):负责加载 <JAVA H O ME>\lib\ext 目录中,或者被 java.ext.dirs 系统变量所指定的路径中所有的类库。
    3. 应用程序类加载器(AppClassLoader):面向用户的加载器,负责加载用户类路径(ClassPath)上的所有类库,可以在代码中使用该类加载器。

除了BootstrapClassLoader加载器,其他的均由Java实现,且全部继承自Java.lang.ClassLoader

  1. 双亲委派模型


    image.png
    双亲委派的工作流程为:
    • 当一个类加载器收到了类加载的请求,首先会判断当前类是否被加载过,若加载过则直接返回该类。
    • 若没有被加载过,会先将该请求委派给父类加载器去完成。
    • 该请求会递归的传送到顶层的启动类加载器中。
    • 当父类加载器无法完成该请求时(即搜索范围中没有找到请求所需的类),子加载器才会尝试去加载。
    • 当父类加载器为null时,会使用启动类加载器 BootstrapClassLoader 作为父类加载器。

类加载器之间的父子关系一般不是以继承( Inheritance)的关系来实现的,而是通常使用组合(Composition)关系来复用父加载器的代码。 双亲委派的优点:Java中的类随着加载器一起具备了带有优先级的层次关系。若无层次关系,类都由各个加载器自行去加载,若用户此时编写了一个名为java.lang的类,并放在程序的ClassPath中,那么系统会因多个加载器而产生多个不同的java.lang类(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类), Java 类型体系中最基础的行为也就无从保证,程序将变得混乱。

双亲委派模型的实现源码:

  1. private final ClassLoader parent;
  2. protected Class<?> loadClass(String name, boolean resolve)
  3. throws ClassNotFoundException
  4. {
  5. synchronized (getClassLoadingLock(name)) {
  6. // 首先,检查请求的类是否已经被加载过
  7. Class<?> c = findLoadedClass(name);
  8. if (c == null) {
  9. long t0 = System.nanoTime();
  10. try {
  11. if (parent != null) {//父加载器不为空,调用父加载器loadClass()方法处理
  12. c = parent.loadClass(name, false);
  13. } else {//父加载器为空,使用启动类加载器 BootstrapClassLoader 加载
  14. c = findBootstrapClassOrNull(name);
  15. }
  16. } catch (ClassNotFoundException e) {
  17. //抛出异常说明父类加载器无法完成加载请求
  18. }
  19. if (c == null) {
  20. long t1 = System.nanoTime();
  21. //自己尝试加载
  22. c = findClass(name);
  23. // this is the defining class loader; record the stats
  24. sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
  25. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
  26. sun.misc.PerfCounter.getFindClasses().increment();
  27. }
  28. }
  29. if (resolve) {
  30. resolveClass(c);
  31. }
  32. return c;
  33. }
  34. }
  1. 自定义类加载器


    除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader
    如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader
    若要避免双亲委托机制,可自定义一个类加载器,然后重写loadClass()即可。