类加载器ClassLoader

内置类加载器及其加载路径

  • 启动类加载器BootstrapClassLoader:加载 %JAVA_HOME%/jre/bin 的类库
  • 扩展类加载器ExtClassLoader:加载 %JAVA_HOME%/jre/bin/ext 的类库
  • 应用类加载器AppClassLoader:加载当前应用的classpath的所有类

ClassLoader.getResource() 可以获取类的绝对路径
Class.getResource() 可以获取类的相对路径

在代码中获取当前类加载器和路径

  1. public class JvmPath {
  2. public static void main(String[] args) {
  3. // 启动类加载器
  4. URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
  5. System.out.println("Bootstrap类加载器");
  6. for (URL urL : urLs) {
  7. System.out.println(" ==> "+ urL.toExternalForm());
  8. }
  9. // 扩展类加载器
  10. printClassLoader("扩展类加载器", DemoApplication.class.getClassLoader().getParent());
  11. // 应用类加载器
  12. printClassLoader("应用类加载器", DemoApplication.class.getClassLoader().getParent());
  13. }
  14. private static void printClassLoader(String name, ClassLoader cl) {
  15. if(cl!=null){
  16. System.out.println(name + "ClassLoader ==>" + cl.toString());
  17. printUrlForClassLoader(cl);
  18. }else{
  19. System.out.println(name + "ClassLoader ==> null");
  20. }
  21. }
  22. private static void printUrlForClassLoader(ClassLoader cl) {
  23. Object ucp = insightField(cl, "ucp");
  24. Object path = insightField(ucp, "path");
  25. ArrayList list = (ArrayList) path;
  26. for (Object o : list) {
  27. System.out.println(" ==> "+ o.toString());
  28. }
  29. }
  30. private static Object insightField(Object obj, String fName) {
  31. try {
  32. Field f = null;
  33. if(obj instanceof URLClassLoader){
  34. f = URLClassLoader.class.getDeclaredField(fName);
  35. }else{
  36. f = obj.getClass().getDeclaredField(fName);
  37. }
  38. f.setAccessible(true);
  39. return f.get(obj);
  40. } catch (Exception e) {
  41. e.printStackTrace();
  42. return null;
  43. }
  44. }
  45. }

类加载器机制

即所谓的双亲委托
image.png
image.png

  • 每次委托会从当前类加载器查找缓存,看类是否已经加载,没有则继续委托父加载器自己先不查找路径
  • 到了Bootstrap类加载器也没从缓存中找到,则从自己的加载路径开始找,没找到则交给子加载器再找
  • 自定义类加载器通常继承于AppClassLoader,则自定义ClassLoader会先被委托

类加载器启动时机

既然类加载器是用来加载类的,那么自身是什么时候加载类加载器的

  • Bootstrap类加载器在JVM启动时启动,来加载核心jar包
  • JVM初始化完成后由Launcher创建扩展类加载器和应用类加载器

    JVM启动 —> Bootstrap类加载器 Launcher —> Ext类加载器和App类加载器

注:Launcher是JVM虚拟机的入口类

自定义类加载器

  • 集成ClassLoader类
  • 重写findClass()方法
  • findClass中调用defineClass()方法