欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java Classloader機制用法代碼解析

 更新時間:2018年01月08日 10:05:38   作者:霍少爺  
這篇文章主要介紹了Java Classloader機制用法代碼解析,涉及JDK默認ClassLoader,雙親委托模型,自定義ClassLoader等相關內容,具有一定借鑒價值,需要的朋友可以參考下

做Java開發(fā),對于ClassLoader的機制是必須要熟悉的基礎知識,本文針對Java ClassLoader的機制做一個簡要的總結。因為不同的JVM的實現(xiàn)不同,本文所描述的內容均只限于Hotspot Jvm.

本文將會從JDK默認的提供的ClassLoader,雙親委托模型,如何自定義ClassLoader以及Java中打破雙親委托機制的場景四個方面入手去討論和總結一下。

JDK默認ClassLoader

JDK 默認提供了如下幾種ClassLoader

Bootstrp loader

Bootstrp加載器是用C++語言寫的,它是在Java虛擬機啟動后初始化的,它主要負責加載%JAVA_HOME%/jre/lib,-Xbootclasspath參數(shù)指定的路徑以及%JAVA_HOME%/jre/classes中的類。

ExtClassLoader

Bootstrp loader加載ExtClassLoader,并且將ExtClassLoader的父加載器設置為Bootstrp loader.ExtClassLoader是用Java寫的,具體來說就是 sun.misc.Launcher$ExtClassLoader,ExtClassLoader主要加載%JAVA_HOME%/jre/lib/ext,此路徑下的所有classes目錄以及java.ext.dirs系統(tǒng)變量指定的路徑中類庫。

AppClassLoader

Bootstrp loader加載完ExtClassLoader后,就會加載AppClassLoader,并且將AppClassLoader的父加載器指定為 ExtClassLoader。AppClassLoader也是用Java寫成的,它的實現(xiàn)類是 sun.misc.Launcher$AppClassLoader,另外我們知道ClassLoader中有個getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要負責加載classpath所指定的位置的類或者是jar文檔,它也是Java程序默認的類加載器。

雙親委托模型

Java中ClassLoader的加載采用了雙親委托機制,采用雙親委托機制加載類的時候采用如下的幾個步驟:

當前ClassLoader首先從自己已經加載的類中查詢是否此類已經加載,如果已經加載則直接返回原來已經加載的類。

每個類加載器都有自己的加載緩存,當一個類被加載了以后就會放入緩存,等下次加載的時候就可以直接返回了。

當前classLoader的緩存中沒有找到被加載的類的時候,委托父類加載器去加載,父類加載器采用同樣的策略,首先查看自己的緩存,然后委托父類的父類去加載,一直到bootstrp ClassLoader.

當所有的父類加載器都沒有加載的時候,再由當前的類加載器加載,并將其放入它自己的緩存中,以便下次有加載請求的時候直接返回。

說到這里大家可能會想,Java為什么要采用這樣的委托機制?理解這個問題,我們引入另外一個關于Classloader的概念“命名空間”, 它是指要確定某一個類,需要類的全限定名以及加載此類的ClassLoader來共同確定。也就是說即使兩個類的全限定名是相同的,但是因為不同的 ClassLoader加載了此類,那么在JVM中它是不同的類。明白了命名空間以后,我們再來看看委托模型。采用了委托模型以后加大了不同的 ClassLoader的交互能力,比如上面說的,我們JDK本生提供的類庫,比如hashmap,linkedlist等等,這些類由bootstrp 類加載器加載了以后,無論你程序中有多少個類加載器,那么這些類其實都是可以共享的,這樣就避免了不同的類加載器加載了同樣名字的不同類以后造成混亂。

如何自定義ClassLoader

Java除了上面所說的默認提供的classloader以外,它還容許應用程序可以自定義classloader,那么要想自定義classloader我們需要通過繼承java.lang.ClassLoader來實現(xiàn),接下來我們就來看看在自定義Classloader的時候,我們需要注意的幾個重要的方法:

1.loadClass 方法

loadClass method declare

public Class<?> loadClass(String name) throws ClassNotFoundException

上面是loadClass方法的原型聲明,上面所說的雙親委托機制的實現(xiàn)其實就是在此方法中實現(xiàn)的。下面我們就來看看此方法的代碼來看看它到底如何實現(xiàn)雙親委托的。

loadClass method implement

public Class<?> loadClass(String name) throws ClassNotFoundException
 { 
return loadClass(name, false);
}

從上面可以看出loadClass方法調用了loadcClass(name,false)方法,那么接下來我們再來看看另外一個loadClass方法的實現(xiàn)。

Class loadClass(String name, boolean resolve)

protected synchronized Class<?> loadClass(String name, Boolean resolve) throws ClassNotFoundException  
 {
	// First, check if the class has already been loaded 
	Class c = findLoadedClass(name);
	//檢查class是否已經被加載過了 
	if (c == null)
	{
		try {
			if (parent != null) {
				c = parent.loadClass(name, false);
				//如果沒有被加載,且指定了父類加載器,則委托父加載器加載。
			} else {
				c = findBootstrapClass0(name);
				//如果沒有父類加載器,則委托bootstrap加載器加載   }
			}
			catch (ClassNotFoundException e) {
				// If still not found, then invoke findClass in order     
				// to find the class.     
				c = findClass(name);
				//如果父類加載沒有加載到,則通過自己的findClass來加載。   }
			}
			if (resolve) 
			{
				resolveClass(c);
			}
			return c;
		}

上面的代碼,我加了注釋通過注釋可以清晰看出loadClass的雙親委托機制是如何工作的。 這里我們需要注意一點就是public Class<?> loadClass(String name) throws ClassNotFoundException沒有被標記為final,也就意味著我們是可以override這個方法的,也就是說雙親委托機制是可以打破的。另外上面注意到有個findClass方法,接下來我們就來說說這個方法到底是搞末子的。

2.findClass

我們查看java.lang.ClassLoader的源代碼,我們發(fā)現(xiàn)findClass的實現(xiàn)如下:

 protected Class<?> findClass(String name) throws ClassNotFoundException
 { 
throw new ClassNotFoundException(name);
}

我們可以看出此方法默認的實現(xiàn)是直接拋出異常,其實這個方法就是留給我們應用程序來override的。那么具體的實現(xiàn)就看你的實現(xiàn)邏輯了,你可以從磁盤讀取,也可以從網絡上獲取class文件的字節(jié)流,獲取class二進制了以后就可以交給defineClass來實現(xiàn)進一步的加載。defineClass我們再下面再來描述。 ok,通過上面的分析,我們可以得出如下結論:

我們在寫自己的ClassLoader的時候,如果想遵循雙親委托機制,則只需要override findClass.

3.defineClass

我們首先還是來看看defineClass的源碼:

defineClass

protected final Class<?> defineClass(String name, byte[] b, int off, int len) 
throws ClassFormatError
{   
 return defineClass(name, b, off, len, null);
}

從上面的代碼我們看出此方法被定義為了final,這也就意味著此方法不能被Override,其實這也是jvm留給我們的唯一的入口,通過這個唯一的入口,jvm保證了類文件必須符合Java虛擬機規(guī)范規(guī)定的類的定義。此方法最后會調用native的方法來實現(xiàn)真正的類的加載工作。

Ok,通過上面的描述,我們來思考下面一個問題:

假如我們自己寫了一個java.lang.String的類,我們是否可以替換調JDK本身的類?

答案是否定的。我們不能實現(xiàn)。為什么呢?我看很多網上解釋是說雙親委托機制解決這個問題,其實不是非常的準確。因為雙親委托機制是可以打破的,你完全可以自己寫一個classLoader來加載自己寫的java.lang.String類,但是你會發(fā)現(xiàn)也不會加載成功,具體就是因為針對java.*開頭的類,jvm的實現(xiàn)中已經保證了必須由bootstrp來加載。

不遵循“雙親委托機制”的場景

上面說了雙親委托機制主要是為了實現(xiàn)不同的ClassLoader之間加載的類的交互問題,被大家公用的類就交由父加載器去加載,但是Java中確實也存在父類加載器加載的類需要用到子加載器加載的類的情況。下面我們就來說說這種情況的發(fā)生。

Java中有一個SPI(ServiceProviderInterface)標準,使用了SPI的庫,比如JDBC,JNDI等,我們都知道JDBC需要第三方提供的驅動才可以,而驅動的jar包是放在我們應用程序本身的classpath的,而jdbc本身的api是jdk提供的一部分,它已經被bootstrp加載了,那第三方廠商提供的實現(xiàn)類怎么加載呢?這里面JAVA引入了線程上下文類加載的概念,線程類加載器默認會從父線程繼承,如果沒有指定的話,默認就是系統(tǒng)類加載器(AppClassLoader),這樣的話當加載第三方驅動的時候,就可以通過線程的上下文類加載器來加載。

另外為了實現(xiàn)更靈活的類加載器OSGI以及一些Javaappserver也打破了雙親委托機制。

總結

以上就是本文關于Java Classloader機制用法代碼解析的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

相關文章

  • IDEA中maven無法下載源碼的解決方法

    IDEA中maven無法下載源碼的解決方法

    這篇文章主要為大家詳細介紹了當IDEA中maven無法下載源碼時改如何解決,文中通過圖文為大家進行了詳細講解,需要的小伙伴可以參考一下
    2023-08-08
  • 關于junit單元測試@Test的使用方式

    關于junit單元測試@Test的使用方式

    這篇文章主要介紹了關于junit單元測試@Test的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 解析ConcurrentHashMap:成員屬性、內部類、構造方法

    解析ConcurrentHashMap:成員屬性、內部類、構造方法

    ConcurrentHashMap是由Segment數(shù)組結構和HashEntry數(shù)組結構組成。Segment的結構和HashMap類似,是一種數(shù)組和鏈表結構,今天給大家普及java面試常見問題---ConcurrentHashMap知識,一起看看吧
    2021-06-06
  • win10 下 idea2020安裝 JetBrains-agent.jar 包后閃退的問題及解決辦法

    win10 下 idea2020安裝 JetBrains-agent.jar 包后閃退的問題及解決辦法

    這篇文章主要介紹了win10 下 idea2020安裝 JetBrains-agent.jar 包后閃退的解決辦法,本文給大家?guī)碓蚍治黾敖鉀Q方法,需要的朋友可以參考下
    2020-08-08
  • Kotlin基礎教程之伴生對象,getter,setter,內部,局部,匿名類,可變參數(shù)

    Kotlin基礎教程之伴生對象,getter,setter,內部,局部,匿名類,可變參數(shù)

    這篇文章主要介紹了Kotlin基礎教程之伴生對象,getter,setter,內部,局部,匿名類,可變參數(shù)的相關資料,需要的朋友可以參考下
    2017-05-05
  • SpringBoot使用swagger生成api接口文檔的方法詳解

    SpringBoot使用swagger生成api接口文檔的方法詳解

    在之前的文章中,使用mybatis-plus生成了對應的包,在此基礎上,我們針對項目的api接口,添加swagger配置和注解,生成swagger接口文檔,需要的可以了解一下
    2022-10-10
  • Java排序算法總結之冒泡排序

    Java排序算法總結之冒泡排序

    這篇文章主要介紹了Java排序算法總結之冒泡排序,較為詳細的分析了冒泡排序的原理與java實現(xiàn)技巧,需要的朋友可以參考下
    2015-05-05
  • Spring MVC簡介_動力節(jié)點Java學院整理

    Spring MVC簡介_動力節(jié)點Java學院整理

    Spring MVC屬于SpringFrameWork的后續(xù)產品,已經融合在Spring Web Flow里面。今天先從寫一個Spring MVC的HelloWorld開始,讓我們看看如何搭建起一個Spring mvc的環(huán)境并運行程序,感興趣的朋友一起學習吧
    2017-08-08
  • mybatis中幾種typeHandler的定義使用詳解

    mybatis中幾種typeHandler的定義使用詳解

    本文主要介紹了mybatis中幾種typeHandler的定義使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Spring 緩存抽象示例詳解

    Spring 緩存抽象示例詳解

    Spring框架自身并沒有實現(xiàn)緩存解決方案,但是從3.1開始定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口,提供對緩存功能的聲明,能夠與多種流行的緩存實現(xiàn)集成。這篇文章主要介紹了Spring 緩存抽象 ,需要的朋友可以參考下
    2018-09-09

最新評論