关于ClassLoader原理网上简介颇多,但是讲的好的,能让人简而易懂的理解的,个人觉得以下这个片博客写的不错。
java虚拟机原理图解 5. JVM类加载器机制与类加载过程
为了理解本文,我从代码角度来分析JVM加载机制和类加载过程
首先:
BootStrapClassLoader----引导类加载器---C++编写,封装入JVM中
ExtClassLoader----------扩展类加载器---Launcher内部类
AppClassLoader----------应用类加载器/系统类加载器---Launcher内部类
当我们在IJ或者eclipse中run一个带main方法的类时或者在linux下java batchmain时,
在run之前,我们的java虚拟机是关闭的状态。run后,虚拟机开启,BootStrapClassLoader会加载{JAVA_HOME}/jre/lib下的jar包,
其中有一个rt.jar的包中,我们会找到一个sun.misc.Launcher类,既然BootStrapClassLoader加载rt.jar必然会加载Launcher,
这里我贴了源代码:
package sun.misc; import ... public class Launcher { private static URLStreamHandlerFactory factory = new Launcher.Factory();
//我们可以看出这个单例模式,私有化launcher,当BootStrap加载Launcher时,自动创建Launcher的实例 private static Launcher launcher = new Launcher(); private static String bootClassPath = System.getProperty("sun.boot.class.path"); private ClassLoader loader; private static URLStreamHandler fileHandler; //单例模式提供的public get方法 public static Launcher getLauncher() { return launcher; } //构造方法,会实例化内部类ExtClassLoader和AppClassLoader public Launcher() { Launcher.ExtClassLoader var1; try {
//实例化ExtClassLoader var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try {
//实例化AppClassLoader this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); if (var2 != null) { SecurityManager var3 = null; if (!"".equals(var2) && !"default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); System.setSecurityManager(var3); } }
AppClassLoader and ExtClassLoader拥有相同的以下继承关系:
AppClassLoader extends URLClassLoader extends SecureClassLoader extends ClassLoader
ExtClassLoader extends URLClassLoader extends SecureClassLoader extends ClassLoader
ClassLoader是个抽象类,但是有构造方法,如下
1 //代码我以略掉大部分 2 public abstract class ClassLoader { 3 private final ClassLoader parent; 4 5 private ClassLoader(Void unused, ClassLoader parent) { 6 this.parent = parent; 7 } 8 }
AppClassLoader和ExtClassLoader实例化这个部分我也贴出代码:
1 static class AppClassLoader extends URLClassLoader { 2 final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this); 3 4 public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException { 5 final String var1 = System.getProperty("java.class.path"); 6 final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1); 7 return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction() { 8 public Launcher.AppClassLoader run() { 9 URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
//此处返回的对象根据java多态性回调用Classloader抽象类构造方法,其parent传值为var0,即ExtClassLoader 10 return new Launcher.AppClassLoader(var1x, var0); 11 } 12 }); 13 } 14 15 AppClassLoader(URL[] var1, ClassLoader var2) { 16 super(var1, var2, Launcher.factory); 17 this.ucp.initLookupCache(this); 18 } 19 20 public Class> loadClass(String var1, boolean var2) throws ClassNotFoundException { 21 int var3 = var1.lastIndexOf(46); 22 if (var3 != -1) { 23 SecurityManager var4 = System.getSecurityManager(); 24 if (var4 != null) { 25 var4.checkPackageAccess(var1.substring(0, var3)); 26 } 27 } 28 29 if (this.ucp.knownToNotExist(var1)) { 30 Class var5 = this.findLoadedClass(var1); 31 if (var5 != null) { 32 if (var2) { 33 this.resolveClass(var5); 34 } 35 36 return var5; 37 } else { 38 throw new ClassNotFoundException(var1); 39 } 40 } else { 41 return super.loadClass(var1, var2); 42 } 43 }
1 static class ExtClassLoader extends URLClassLoader { 2 public static Launcher.ExtClassLoader getExtClassLoader() throws IOException { 3 final File[] var0 = getExtDirs(); 4 5 try { 6 return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction() { 7 public Launcher.ExtClassLoader run() throws IOException { 8 int var1 = var0.length; 9 10 for(int var2 = 0; var2 < var1; ++var2) { 11 MetaIndex.registerDirectory(var0[var2]); 12 } 13 //此处返回的对象根据java多态性回调用Classloader抽象类构造方法,其parent传值为null。 14 return new Launcher.ExtClassLoader(var0); 15 } 16 }); 17 } catch (PrivilegedActionException var2) { 18 throw (IOException)var2.getException(); 19 } 20 }
至此JVM类加载器初始化完毕。然后loader.loadClass();
此时我们根据类加载规则,去加载main类,如果发现有main()方法,就开始直接执行,直到exit。
我们需要注意的是,类加载器加载一个类时,并不是去读代码看看那些类需要加载,这里涉及到最重要的东西那就是:
Import,因为我们需要的类都是引入进来的,引入包直接加载就好了。
而setContextClassLoader可以打破双亲加载机制。典型应用---tomcat启动类BootStrap定义了三个自定义加载器,
catalinaClassLoader
commonClassLoader
sharedClassLoader
......