關於ClassLoader原理網上簡介頗多,可是講的好的,能讓人簡而易懂的理解的,我的以爲如下這個片博客寫的不錯。java
java虛擬機原理圖解 5. JVM類加載器機制與類加載過程linux
爲了理解本文,我從代碼角度來分析JVM加載機制和類加載過程tomcat
首先:app
BootStrapClassLoader----引導類加載器---C++編寫,封裝入JVM中eclipse
ExtClassLoader----------擴展類加載器---Launcher內部類ui
AppClassLoader----------應用類加載器/系統類加載器---Launcher內部類this
當咱們在IJ或者eclipse中run一個帶main方法的類時或者在linux下java batchmain時,lua
在run以前,咱們的java虛擬機是關閉的狀態。run後,虛擬機開啓,BootStrapClassLoader會加載{JAVA_HOME}/jre/lib下的jar包,spa
其中有一個rt.jar的包中,咱們會找到一個sun.misc.Launcher類,既然BootStrapClassLoader加載rt.jar必然會加載Launcher,.net
這裏我貼了源代碼:
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<Launcher.AppClassLoader>() { 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<Launcher.ExtClassLoader>() { 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......