JVM类加载-从ClassLoader源码看双亲委托模型
来源:互联网 发布:tensorflow 知乎 编辑:程序博客网 时间:2024/05/16 18:28
其实JVM类加载机制,简单地说就是类管理,也就是我们生成的class文件。
三个步骤:装载(load)、链接(link)、解析(Resolve)、还有初始化(Initialize)
关于网上有很多讲解加载的方式,和调用的方式,还是几个基本的classLoader,这里就不在多描述了。
这里更多的是从源码上来讲解,达到理论结合实际。
首先是ClassLoader这个抽象类,这个是实现自定义类的基础。那么在调用的时候,首先都是调用loadClass这个方法,如图:
<span style="font-size:18px;"> public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); }</span>该方法调用的是一个重载方法loadClass(name,false)方法如图:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // 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; } }
加载类的代码是由Synchronized修饰的代码块,由此可见JVM加载类是线程安全的。
第一行注释很清楚的表示,从当前的类加载器里加载class文件,如果已经加载,就直接返回;不存在就加载;如果返回NULL,表示class文件不在这个类加载器的范围内。
这是就会执行if(c==null)下面的方法,就会去找父加载器(类加载器的整个结构是树形的,这里不多介绍),如果父加载器不存在,就直接找到根加载器(根加载器一定存在),即双亲委任模型。
我们现在开始解析每个被调用方法。
首先看下findLoadedClass方法,如图:
<span style="font-size:18px;"> protected final Class<?> findLoadedClass(String name) { if (!checkName(name)) return null; return findLoadedClass0(name); }</span>该方法首先,校验类名是否正确(类似于 test.demo.Test.class),校验成功后,调用本地方法findLoadedClass0方法。
接着是parent.loadClass(name,false)方法,该方法是重复的,只是对象不同而已,就不介绍了。
接着是findBootstrapClassOrNull方法,如图:
<span style="font-size:18px;"> /** * Returns a class loaded by the bootstrap class loader; * or return null if not found. */ private Class<?> findBootstrapClassOrNull(String name) { if (!checkName(name)) return null; return findBootstrapClass(name); }</span>方式与findLoadedClass方法一样,就是本地调用是findBootstrapClass方法。
如果此时类还不存在,有一个findClass方法的调用。代码如图:
<span style="font-size:18px;"> /** * Finds the class with the specified <a href="#name">binary name</a>. * This method should be overridden by class loader implementations that * follow the delegation model for loading classes, and will be invoked by * the {@link #loadClass <tt>loadClass</tt>} method after checking the * parent class loader for the requested class. The default implementation * throws a <tt>ClassNotFoundException</tt>. */ protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }</span>这里看上去觉得很奇怪,直接就抛一个空异常了,其实根据注释所说,就是自定义的类加载器需要实现这种方法。
为什么要实现这个方法呢?原因就是有些场景会需要通过网络传输的方式进行加载类(该类其实是在远程服务器上的),在很多地方就会用到,例如远程调用等技术。
具体的实现例子,在URLClassLoader里就有体现,这里暂不介绍。
最后是调用了resolveClass方法,代码如图:
<span style="font-size:18px;"> protected final void resolveClass(Class<?> c) { resolveClass0(c); } private native void resolveClass0(Class<?> c);</span>
这个方法很简单,主要是重新进行解析类,该解析主要是对所有的属性/方法调用是否存在、相应的权限(如private、public等)进行验证。那么为什么默认都是传入false呢?
那是因为是否需要更强的安全机制的检测,
另一个情况是类加载是无序的,会导致类链接不成功。
这里有个状态位的控制,主要是可能有些场景需要更严格的对类进行验证。
这里要注意的是:
类为什么是树形结构,主要就是安全,因为类加载器都是从不同的目录进行加载的(网上有介绍三个最基础的类加载器Bootstrap ClassLoader\Extension ClassLoader\System ClassLoader加载的默认目录,这里不多介绍),所以用这种目录的方式来进行权限管理,常用都是使用classpath系统变量,如果我想自己定义一个加载目录,那么就需要实现自己的类加载器,进行相应的权限管理。
另外这个抽象类,实现了只是从本地进行加载类的方式,如果需要进行远程加载类,那么也需要实现自己的类加载器(URLClassLoader)。
1 0
- JVM类加载-从ClassLoader源码看双亲委托模型
- 【jvm】---classLoader 双亲委派模型
- jvm 类加载机制双亲委托机制
- JVM类加载双亲委派模型
- JVM类加载的双亲委派模型
- 理解ClassLoader双亲委托模型关键
- 黑马程序员--05.类加载器--03【从JVM加载类的过程再看类加载器】【从Java源码再看双亲委派模型】
- classloader加载的双亲委托模式
- JVM 类加载器介绍及其双亲委托机制
- java ClassLoader类解析-双亲委托机制
- java ClassLoader类解析-双亲委托机制
- JVM:类加载器之双亲委派模型
- 【深入理解JVM】:类加载器与双亲委派模型
- jvm类加载器和双亲委派模型
- JVM类加载时经典的双亲委派模型
- 理解jvm类加载机制(双亲委派模型)
- 【JVM】类加载器与双亲委派模型(一)
- 【JVM】类加载器与双亲委派模型(二)
- 无法获得锁 /var/lib/dpkg/lock - open (11: 资源临时不可用)
- Mac:特殊符号输入方法
- ListView专题
- android 自定义dialog
- 用GDB调试程序1
- JVM类加载-从ClassLoader源码看双亲委托模型
- host 中用virsh shutdown 关闭vms
- iOS中启动缺少图片会出现下面有黑边的问题
- PopupWindow细节
- HDU 4664 Triangulation (SG函数,打表找规律)
- css字体em和px
- ubuntu安装最新gnome
- 触发器分为事前触发和事后触发,这两种触发有和区别。
- 启动其他APK的Activity方法