0.1 、Spring 源碼學習-JVM類加載器-雙親委派模型-Spring 中類加載機制

JVM 類加載機制

/**
* 獲取類加載器的測試方法
*/
@Test
public void test2() {
	//獲取Test類的類加載器 sun.misc.Launcher$AppClassLoader@4dc63996
	ClassLoader c  = Test.class.getClassLoader();  
       System.out.println(c); 
       //獲取c這個類加載器的父類加載器 sun.misc.Launcher$ExtClassLoader@28a418fc
       ClassLoader c1 = c.getParent(); 
       System.out.println(c1); 
       // getClassLoader() returning null indicates the bootstrap ClassLoader
       //獲取c1這個類加載器的父類加載器 ,null,因爲Bootstrp loader是C++編寫的,依java的觀點來看,邏輯上並不存在Bootstrap Loader的類實體
       //根裝載器:Bootstrp loader
       //用C++語言寫的,它是在Java虛擬機啓動後初始化的,主要負責加載%JAVA_HOME%/jre/lib,
       //* -Xbootclasspath參數指定的路徑以及%JAVA_HOME%/jre/classes中的類。
       ClassLoader c2 = c1.getParent();
       System.out.println(c2);
       
       //獲取系統默認的ClassLoader sun.misc.Launcher$AppClassLoader@4dc63996
       ClassLoader c3=ClassLoader.getSystemClassLoader();
       System.out.println(c3);
       //獲取創建當前線程的類加載器 
       ClassLoader c4= Thread.currentThread().getContextClassLoader();
       System.out.println(c4);
}

雙親委派模型

簡單說就是,先由自己的父類加載需要的類,一直向上傳遞,如果沒有再由自己加載
類加載器可以重寫,但是核心類是不允許使用自己的類加載器加載的,比如 jdk 核心包 java.lang.String ,只允許 bootstrap ClassLoader 進行加載

  • BootStrap ClassLoader:稱爲啓動類加載器,是Java類加載層次中最頂層的類加載器,負責加載JDK中的核心類庫,JAVA_HOME/JRE/lib/,如:rt.jar、resources.jar、charsets.jar等
  • Extension ClassLoader:稱爲擴展類加載器,負責加載Java的擴展類庫,默認加載JAVA_HOME/JRE/lib/ext/目下的所有jar
  • App ClassLoader:稱爲系統類加載器,負責加載應用程序classpath目錄下的所有jar和class文件
自定義類加載器的原則:組合而非繼承

這裏類加載器之間的父子關係一般不會以繼承的關係來實現,而是都使用組合關係來複用父加載器的代碼。
這意味着,當你在自定義類加載器時,也應該先委託父加載器即App ClassLoader進行加載。
那麼問題來了,既然雙親委派模型只是一個規範,那我可以直接使用自定義加載器加載 String 類嗎?答案是:不可以。因爲JVM會檢測,即使你不遵守雙親委派模型,你也無法加載核心類庫的類,JVM自己會檢測。

Spring 類加載機制

入口 AbstractApplicationContext.prepareBeanFactory
beanFactory.setBeanClassLoader(getClassLoader());
DefaultResourceLoader.getClassLoader()

org.springframework.core.io.DefaultResourceLoader

/**
* Return the ClassLoader to load class path resources with.
 * <p>Will get passed to ClassPathResource's constructor for all
 * ClassPathResource objects created by this resource loader.
 * @see ClassPathResource
 */
@Override
public ClassLoader getClassLoader() {
	//如果指定了類加載器就返回指定的類加載器,否則獲取線程類加載器->不存在就獲取ClassUtils類加載器-> 不存在就獲取系統默認類加載器
	return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
}
ClassUtils.getDefaultClassLoader()

org.springframework.util.ClassUtils.getDefaultClassLoader()
看中文註釋

/**
* Return the default ClassLoader to use: typically the thread context
 * ClassLoader, if available; the ClassLoader that loaded the ClassUtils
 * class will be used as fallback.
 * <p>Call this method if you intend to use the thread context ClassLoader
 * in a scenario where you clearly prefer a non-null ClassLoader reference:
 * for example, for class path resource loading (but not necessarily for
 * {@code Class.forName}, which accepts a {@code null} ClassLoader
 * reference as well).
 * @return the default ClassLoader (only {@code null} if even the system
 * ClassLoader isn't accessible)
 * @see Thread#getContextClassLoader()
 * @see ClassLoader#getSystemClassLoader()
 */
public static ClassLoader getDefaultClassLoader() {
	ClassLoader cl = null;
	try {
		//獲取當前線程類加載器
		cl = Thread.currentThread().getContextClassLoader();
	}
	catch (Throwable ex) {
		// Cannot access thread context ClassLoader - falling back...
	}
	//如果線程類加載器爲null
	if (cl == null) {
		// No thread context class loader -> use class loader of this class.
		//獲取當前類的類加載器
		cl = ClassUtils.class.getClassLoader();
		if (cl == null) {
			// getClassLoader() returning null indicates the bootstrap ClassLoader
			//getClassLoader() 爲 null 說明是 bootstrap ClassLoader 類加載器,該加載器爲 C++ 編寫,故從Java 角度看是 null
			try {
				//獲取當前系統的類加載器
				cl = ClassLoader.getSystemClassLoader();
			}
			catch (Throwable ex) {
				// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
			}
		}
	}
	return cl;
}

延伸閱讀:破壞雙親委派模型

Tomcat 類加載器之爲何違背雙親委派模型

參考資料

[1]、https://www.jianshu.com/p/554c138ca0f5 (類加載機制)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章