最近看了看ClassLoader,網上的博客挺多的,大部分都是你抄我的,我抄你的。在他們的基礎上,自己打算寫一篇,自己對ClassLoader的分析,也就是對現有blog的總結吧。
ClassLoader初始化源碼。
在openjdk中可以看到下面的代碼。
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"); } // 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"); } // Also set the context class loader for the PRimordial thread. Thread.currentThread().setContextClassLoader(loader); // Finally, install a security manager if requested String s = System.getProperty("java.security.manager"); if (s != null) { SecurityManager sm = null; if ("".equals(s) || "default".equals(s)) { sm = new java.lang.SecurityManager(); } else { try { sm = (SecurityManager)loader.loadClass(s).newInstance(); } catch (IllegalaccessException e) { } catch (InstantiationException e) { } catch (ClassNotFoundException e) { } catch (ClassCastException e) { } } if (sm != null) { System.setSecurityManager(sm); } else { throw new InternalError( "Could not create SecurityManager: " + s); } }}可以看到在Launcher構造函數的執行過程如下:
通過ExtClassLoader.getExtClassLoader()創建了ExtClassLoader;
通過AppClassLoader.getAppClassLoader(ExtClassLoader)創建了AppClassLoader,并將ExtClassLoader設為AppClassLoader的parent ClassLoader;
通過Thread.currentThread().setContextClassLoader(loader)把AppClassLoader設為線程的上下文 ClassLoader;在jdk中默認了3種的ClassLoader:BootStrapClassLoader、ExtensionClassLoader和AppClassLoader。
BootStrapClassLoader:它是最頂層的類加載器,是由C++編寫而成, 已經內嵌到JVM中了。在JVM啟動時會初始化該ClassLoader,它主要用來讀取Java的 核心類庫JRE/lib/rt.jar中所有的class文件,這個jar文件中包含了java規范定義的所有接口及實現。ExtensionClassLoader:它是用來讀取Java的一些擴展類庫,如讀取JRE/lib/ext/*.jar中的包等(這里要注意,有些版本的是沒有ext這個目錄的)。AppClassLoaderBootstrp loader加載完ExtClassLoader后,就會加載AppClassLoader,并且將AppClassLoader的父加載器指定為 ExtClassLoader。AppClassLoader也是用Java寫成的,它的實現類是 sun.misc.Launcher$AppClassLoader,另外我們知道ClassLoader中有個getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要負責加載classpath所指定的位置的類或者是jar文檔,它也是Java程序默認的類加載器。private final ClassLoader parent; 父類的加載器,所有的新的變量都必須在它之后,英文: The parent class loader for delegation.Note: VM hardcoded the offset of this field, thus all new fields must be added after it.
private final ConcurrentHashMap parallelLockMap; 當前ClassLoader在并發情況下,一個鎖的的對象。 Maps class name to the corresponding lock object when the current class loader is parallel capable. Note: VM also uses this field to decide if the current class loader is parallel capable and the appropriate lock object for class loading.
private final Map package2cert;
每個包的證書,是個HashTable
private static final Certificate[] nocerts = new Certificate[0];
Shared among all packages with unsigned classes
private final Vector> classes = new Vector<>(); 這個class loader加載的所有類,這些類是從開始被GC到gc結束 The classes loaded by this class loader. The only purpose of this table is to keep the classes from being GC’ed until the loader is GC’ed.
private final ProtectionDomain defaultDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), null, this, null);
貌似是讀寫的策略,The “default” domain. Set as the default ProtectionDomain on newly created classes.
private final Set domains;
The initiating protection domains for all classes loaded by this loader
私有的構造函數
private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; if (ParallelLoaders.isRegistered(this.getClass())) { parallelLockMap = new ConcurrentHashMap<>(); package2certs = new ConcurrentHashMap<>(); domains = Collections.synchronizedSet(new HashSet<ProtectionDomain>()); assertionLock = new Object(); } else { // no finer-grained lock; lock on the classloader instance parallelLockMap = null; package2certs = new Hashtable<>(); domains = new HashSet<>(); assertionLock = this; } }也就是分為當前的ClassLoader是否被加載2種情況:ParallelLoaders.isRegistered(this.getClass())來判斷是否可以并行
保護性的構造函數
protected ClassLoader(ClassLoader parent) { this(checkCreateClassLoader(), parent); } protected ClassLoader() { this(checkCreateClassLoader(), getSystemClassLoader()); }checkCreateClassLoader():是校驗下創建ClassLoader的權限 parent:是創建ClassLoader的父節點 getSystemClassLoader():是獲取系統的ClassLoader,作為當前節點的父節點 3.loadClass
resolve:在虛擬機中找到一個類二進制,再根據resolve參數判斷Classloader用來鏈接一個類
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; } }先進行getClassLoadingLock(以后會詳細分析),然后查找已加載的類,在從父類ClassLoader查找,最后查找Bootstrap的ClassLoader
resolveClass:鏈接指定的類。這個方法給Classloader用來鏈接一個類,如果這個類已經被鏈接過了,那么這個方法只做一個簡單的返回。否則,這個類將被按照 Java?規范中的Execution描述進行鏈接
http://www.hollischuang.com/archives/199
新聞熱點
疑難解答