之前也有接触过这方面的知识,但都是看过之后就忘记了,这次做一下学习记录加深自己的对这方面知识的印象。
在java中,通过ClassLoader或者它的子类将字节码文件加载到jvm中,装载过程在此不再说明,本文重点是分析双亲委派模型在源码中的实现。JVM预定义有三种类加载器,当一个 JVM启动的时候,Java缺省开始使用如下三种类加载器:
1)引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader。它负责将<Java_Runtime_Home>/lib下面的核心类库或-Xbootclasspath选项指定的jar包加载到内存中。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作
2)扩展类加载器(extensions class loader):该类加载器在此目录里面查找并加载 Java 类。扩展类加载器是由Sun的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。它负责将< Java_Runtime_Home >/lib/ext或者由系统变量-Djava.ext.dirs指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器
3)系统类加载器(system class loader):系统类加载器是由 Sun的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径java -classpath或-Djava.class.path变量所指的目录下的类库加载到内存中。开发者可以直接使用系统类加载器。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它
下面通过代码分析,代码位于ClassLoader类中:
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 { //如果没有父类加载器,则调用启动类加载类的方法查看类是否被加载,调用本地方法 findBootstrapClass c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } //如果无法从父类加载器或者启动类加载器获取到类的加载信息,则通过调用自定义findClass方法加载类 if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //ClassLoader类中的findClass方法为空实现 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()方法,一般重写findClass()方法即可,否则容易破环双亲委派机制。