浅谈 JVM 类加载器与类加载机制 时间: 2018-03-15 20:58 分类: JVM ####概述 类从被加载到虚拟机内存开始,到卸载出内存位置,它的生命周期分为以下 7 个阶段: 加载->验证->准备->解析->初始化->使用->卸载 整个过程涉及到的东西非常多,目前个人理解还比较有限,就不做过多分析,本文主要就类的加载器及加载模型做个简单介绍。 ####类加载器介绍 在 Java 虚拟机中,可以将类加载器细分为以下 4 种: * 启动类加载器(Bootstrap ClasssLoader) * 扩展类加载器(Extension ClassLoader) * 应用程序类加载器(Application ClassLoader) * 用户自定义类加载器(User ClassLoader) 下面简单说下它们各自的功能。 #####启动类加载器(Bootstrap ClasssLoader) 这个类加载器主要负责将放在`$JAVA_HOME/lib`中的,或者被`-Xbootclasspath`参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。 #####扩展类加载器(Extension ClassLoader) 该类加载器它负责将`$JAVA_HOME/lib/ext`中的,或者被`java.ext.dirs`系统环境变量所指定的路径中的所有类加载到虚拟机内存中,相比`启动类加载器`,我们可以将一些第三方的类库放到`$JAVA_HOME/lib/ext`目录中,扩展类也是会加载的,这种暴力的使用场景也很常见,有时候在我们的项目中类冲突了或者其他原因导致找不到类,这个时候就将该类的 jar 包直接丢进`$JAVA_HOME/lib/ext`目录,问题即可暂时解决。 #####应用程序类加载器(Application ClassLoader) 这个类加载器是`ClassLoader`中的`getSystemClassLoader`方法的返回值,所以一般也称作系统类加载器,它负责加载用户类路径(ClassPath)中所包含的类库。 #####用户自定义类加载器(User ClassLoader) 顾名思义,这种类加载器是由程序员通过继承`ClassLoader`自己实现的。 ####类加载模型 以上 4 种类加载器通常情况下都不是单独存在的,而是一起配合来完成加载工作的,比如按以下的关系进行配合加载:  加载关系是这样的:除了启动类加载器外,其他类型的类加载器加载类的时候,都不会直接自己去加载,而是去让它的父节点去加载,如果父节点加载失败,最后再由自己来加载。 上面这种类加载器之间的这种层次关系,称为类加载器的`双亲委派模型(Parents Delegation Model)`。 我们可以通过`ClassLoader`的`loadClass`方法看到上面那种加载关系: ```java 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; } } ``` 只要除了`启动类加载器`以外所有的类加载器都遵循上面的加载机制,并且之间设置好父子关系,那么就构成了`双亲委派模型`,一般来说,用户自定义类加载器,继承`ClassLoader`之后,不需要重写上面的`loadClass`方法,只需要重写`findClass`方法即可,这样就确保写出来的类加载器是符合`双亲委派模型`的。 ####总结 革命尚未成功,同志还需继续努力。 标签: classloader