类加载器(1)-基础

类加载器加载顺序

  1. Bootstrap ClassLoader
  2. ExtClassLoader
  3. AppClassLoader

为啥加载顺序是这样的?从Launcher类说起

Launcher类

分析Launcher构造器源码

 public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
            //AppClassLoader 父加载器 ExtClassLoader
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }

        Thread.currentThread().setContextClassLoader(this.loader);
        .......
}

Launcher类中封装了ExtClassLoader和AppClassLoader

分析ExtClassLoader和AppClassLoader源码

static class ExtClassLoader extends URLClassLoader {
        public ExtClassLoader(File[] var1) throws IOException {
            // ExtClassLoader  父加载器 null
            super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
            ......
        }
}

static class AppClassLoader extends URLClassLoader {
        .......
}

从以上源码可知:

1)AppClassLoader的父加载器是ExtClassLoader

2)ExtClassLoader的父加载器是null

3)Thread.currentThread().getContextClassLoader()获取的是AppClassLoader

那为啥说ExtClassLoader父加载器是Bootstrap ClassLoader?分析ClassLoader源码

ClassLoader类

分析构造函数

private ClassLoader(Void unused, ClassLoader parent) {
        this.parent = parent;
        ......
}

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

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

根据构造函数可知:

1)每个类加载器都有一个父加载器

2)如果ClassLoader创建时没有指定parent,那它的parent默认从getSystemClassLoader()获取,就是AppClassLoader

分析loadClass方法源码

 protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先, 检查类是否已经被加载
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        //如果父加载器不为空
                        c = parent.loadClass(name, false);
                    } else {
                        //如果父加载器为空,使用Bootstrap ClassLoader加载
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // 如果还是没找到类,那就使用findclass方法查找类
                    // 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;
        }
    }

分析loadClass方法源码可知:

当使用AppClassLoader加载类的时候,先递归调用AppClassLoader的父加载器ExtClassLoader加载类,然后递归调用ExtClassLoader的父加载器加载类,因为ExtClassLoader的父加载器是null,最终会使用Bootstrap ClassLoader加载类(Bootstrap ClassLoader是c++方法编写),所以我们可以认为ExtClassLoader的父加载器是Bootstrap ClassLoader

加载器加载类的路径

  1. Bootstrap ClassLoader :System.getProperty("sun.boot.class.path")
  2. ExtClassLoader :System.getProperty("java.ext.dirs")
  3. AppClassLoader :System.getProperty("java.class.path")

查看sun.misc.Launcher.AppClassLoader源码

 public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
            final String var1 = System.getProperty("java.class.path");  
            .......         
 }

查看sun.misc.Launcher.ExtClassLoader源码

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

查看Launcher源码

private static String bootClassPath = System.getProperty("sun.boot.class.path");

测试例子

public class ClassLoadTest {
    public static void main(String[] args) {
        ClassLoader cl = ClassLoadTest.class.getClassLoader();
        System.out.println("ClassLoader is:"+cl.toString());
        System.out.println("ClassLoader is:"+Thread.currentThread().getContextClassLoader());
        System.out.println("ClassLoader is:"+cl.getParent().toString());
        System.out.println("ClassLoader is:"+ClassLoader.getSystemClassLoader().toString());
        System.out.println("ClassLoader is:"+Launcher.getLauncher().getClassLoader().toString());
        System.out.println("ClassLoader is:"+Launcher.getLauncher().getClassLoader().getParent().toString());

        // String 和 int 的 classload 都是 null , 是由Bootstrap ClassLoader 加载
        //ystem.out.println(int.class.getClassLoader().toString());
        //System.out.println(String.class.getClassLoader().toString());
    }
}

测试结果

ClassLoader is:sun.misc.Launcher$AppClassLoader@18b4aac2
ClassLoader is:sun.misc.Launcher$AppClassLoader@18b4aac2
ClassLoader is:sun.misc.Launcher$ExtClassLoader@6ff3c5b5
ClassLoader is:sun.misc.Launcher$AppClassLoader@18b4aac2
ClassLoader is:sun.misc.Launcher$AppClassLoader@18b4aac2
ClassLoader is:sun.misc.Launcher$ExtClassLoader@6ff3c5b5

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值