专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
51好读  ›  专栏  ›  ImportNew

ClassLoader 揭秘( 上 )

ImportNew  · 公众号  · Java  · 2017-08-20 12:18

正文

请到「今天看啥」查看全文



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

}


执行以下代码即可获得classpath加载路径:


System.out.println(System.getProperty("java.class.path"));


2.4 三种加载器联系


用一张图来表示三张图的关系如下:



用户自定义的无参加载器的父类加载器默认是AppClassloader加载器,而AppClassloader加载器的父加载器是ExtClassloader,通过下面代码可以验证:


ClassLoader.getSystemClassLoader().getParent()


一般我们都认为ExtClassloader的父类加载器是BootStarpClassloader,但是其实他们之间根本是没有父子关系的,只是在ExtClassloader找不到要加载类时候会去委托BootStrap加载器去加载。


通过如下代码可以知道父加载器为null


ClassLoader.getSystemClassLoader().getParent().getParent()


2.5 类加载器原理


Java类加载器使用的是委托机制,也就是子类加载器在加载一个类时候会让父类来加载,那么问题来了,为啥使用这种方式那?因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时就被引导类加载器(Bootstrcp ClassLoader)加载,所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。下面我们从源码看如何实现委托机制:


protected Class> loadClass(Stringname,boolean resolve)

throws ClassNotFoundException

{

synchronized (getClassLoadingLock(name)) {

// 首先从jvm缓存查找该类

Class c = findLoadedClass(name);  (1)           if (c ==null) {

longt0 = System.nanoTime();

try {  //然后委托给父类加载器进行加载

if (parent !=null) {

c = parent.loadClass(name,false);  (2)

} else {  //如果父类加载器为null,则委托给BootStrap加载器加载

c = findBootstrapClassOrNull(name);  (3)

}

} catch (ClassNotFoundExceptione) {

// ClassNotFoundException thrown if class not found

// from the non-null parent class loader

}

if (c ==null) {

// 若仍然没有找到则调用findclass查找

// to find the class.

longt1 = System.nanoTime();

c = findClass(name);  (4)                   // 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);

}

returnc;

}

}


分析代码知道首先会执行(1)从jvm缓存查找该类,如何该类之前被加载过,则直接从jvm缓存返回该类,否者看当前类加载器是否有父加载器,如果有的话则委托为父类加载器进行加载(2),否者调用(3)委托为BootStrapClassloader进行加载,如果还是没有找到,则调用当前Classloader的findclass方法进行查找。


从上面源码知道要想修改类加载委托机制,实现自己的载入策略 可以通过覆盖ClassLoader的findClass方法或者覆盖loadClass方法来实现。


2.6 Java中如何构造三种类加载器的结构


下面从源码来分析下JVM是如何构建内置classloader的,具体是rt.jar包里面sun.misc.Launcher类:


public Launcher()

{

ExtClassLoader localExtClassLoader;







请到「今天看啥」查看全文