内容简介:类加载器之间的这种层次关系叫做双亲委派模型。双亲委派模型要求除了顶层的启动类加载器(Bootstrap ClassLoader)外,其余的类加载器都应当有自己的父类加载器。这里的类加载器之间的父子关系一般不是以继承关系实现的,而是用组合实现的。从源码中我们看到
- 启动类加载器 BootStrap ClassLoader :最顶层的类加载器,负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。可以通
System.getProperty("sun.boot.class.path")
查看加载的路径。 - 扩展类加载器 Extention ClassLoader :主要加载目录
%JRE_HOME%\lib\ext
目录下的jar
包和class
文件,或通过java.ext.dirs系统变量指定路径中的类库。也可以通过System.out.println(System.getProperty("java.ext.dirs"))
查看加载类文件的路径。 - 应用程序类加载器 Application ClassLoader :也叫做系统类加载器,可以通过
getSystemClassLoader()
获取,负责加载用户路径classpath
上的类库。如果没有自定义类加载器,一般这个就是默认的类加载器。
类加载层次关系
类加载器之间的这种层次关系叫做双亲委派模型。
双亲委派模型要求除了顶层的启动类加载器(Bootstrap ClassLoader)外,其余的类加载器都应当有自己的父类加载器。这里的类加载器之间的父子关系一般不是以继承关系实现的,而是用组合实现的。
- 下面看一段源码
public class Launcher { private static Launcher launcher = new Launcher(); private static String bootClassPath = System.getProperty("sun.boot.class.path"); public static Launcher getLauncher() { return launcher; } private ClassLoader loader; public Launcher() { // Create the extension class loader ClassLoader extcl; try { extcl = ExtClassLoader.getExtClassLoader(); } catch (IOException e) { throw new InternalError( "Could not create extension class loader", e); } // Now create the class loader to use to launch the application try { loader = AppClassLoader.getAppClassLoader(extcl); } catch (IOException e) { throw new InternalError( "Could not create application class loader", e); } Thread.currentThread().setContextClassLoader(loader); } /* * Returns the class loader used to launch the main application. */ public ClassLoader getClassLoader() { return loader; } /* * The class loader used for loading installed extensions. */ static class ExtClassLoader extends URLClassLoader {} /** * The class loader used for loading from java.class.path. * runs in a restricted security context. */ static class AppClassLoader extends URLClassLoader {} 复制代码
从源码中我们看到
(1) Launcher
初始化的时候创建了 ExtClassLoader
以及 AppClassLoader
,并将 ExtClassLoader
实例传入到 AppClassLoader
中。
(2)虽然上一段源码中没见到创建 BoopStrap ClassLoader
,但是程序一开始就执行了 System.getProperty("sun.boot.class.path")
。
附上 Launcher
相关文章: blog.csdn.net/jyxmust/art…
- 类加载器中的继承关系
AppClassLoader
的父加载器为ExtClassLoader
,ExtClassLoader
的父加载器为null
,BoopStrap ClassLoader
为顶级加载器。
类加载机制-双亲委托
当JVM加载 Test.class
类的时候
- 首先会到自定义加载器中查找,看是否已经加载过,如果已经加载过,则返回该类。
- 如果自定义加载器没有加载过,则询问上一层加载器(即
AppClassLoader
)是否已经加载过Test.class
。 - 如果没有加载过,则询问上一层加载器(
ExtClassLoader
)是否已经加载过。 - 如果没有加载过,则继续询问上一层加载(
BoopStrap ClassLoader
)是否已经加载过。 - 如果
BoopStrap ClassLoader
没有加载过,则到自己指定类加载路径sun.boot.class.path
下查看是否有Test.class
字节码,有则加载并返回加载后的类c = findBootstrapClassOrNull(name)
。 - 如果还是没找到调用
c = findClass(name)
到加载器ExtClassLoader
指定的类加载路径java.ext.dirs
下查找class
文件,有则加载并返回类。 - 依此类推,最后到自定义类加载器指定的路径还没有找到
Test.class
字节码,则抛出异常ClassNotFoundException
。
这里注意
每个自定义的类加载器都需要重写 findClass
方法,该方法的作用是到指定位置查找 class
文件并加载到JVM中,如果找不到则抛出 ClassNotFoundException
异常。
双亲委派模型最大的好处就是让 Java 类同其类加载器一起具备了一种带优先级的层次关系。这句话可能不好理解,我们举个例子。比如我们要加载顶层的Java类—— java.lang.Object
类,无论我们用哪个类加载器去加载 Object
类,这个加载请求最终都会委托给 Bootstrap ClassLoader
,这样就保证了所有加载器加载的 Object
类都是同一个类。
双亲委派模型的实现比较简单,在 java.lang.ClassLoader
的 loadClass
方法中:
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; } } 复制代码
/** * 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>. * * @param name * The <a href="#name">binary name</a> of the class * * @return The resulting <tt>Class</tt> object * * @throws ClassNotFoundException * If the class could not be found * * @since 1.2 */ protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- springMVC容器加载源码分析
- caffe源码阅读(1): 数据加载
- Glide 图片加载框架源码解析
- Tinker源码分析(二):加载补丁
- 【MyBatis源码分析】Configuration加载(下篇)
- 【MyBatis源码分析】Configuration加载(上篇)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
正则表达式在线测试
正则表达式在线测试
HSV CMYK 转换工具
HSV CMYK互换工具