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

Java中JVM的類(lèi)加載器詳解

 更新時(shí)間:2023年07月31日 11:41:42   作者:兔老大RabbitMQ  
這篇文章主要介紹了Java中的類(lèi)加載器詳解,從概念上來(lái)講, 自定義類(lèi)加載器一般指的是程序中由開(kāi)發(fā)人員自定義的類(lèi)加載器,但是Java虛擬機(jī)規(guī)范卻沒(méi)有這么定義,而是將所有派生于抽象類(lèi)ClassLoader的類(lèi)加載器都劃分為自定義類(lèi)加載器,需要的朋友可以參考下

類(lèi)加載過(guò)程

加載->連接->初始化。

連接過(guò)程又可分為三步:驗(yàn)證->準(zhǔn)備->解析。

類(lèi)加載器分類(lèi)

JVM 中內(nèi)置了三個(gè)重要的 ClassLoader,除了 BootstrapClassLoader 其他類(lèi)加載器均由 Java 實(shí)現(xiàn)且全部繼承自java.lang.ClassLoader

  1. 啟動(dòng)類(lèi)加載器(Bootstrap ClassLoader)
    此類(lèi)加載器負(fù)責(zé)將存放在 <JRE_HOME>\lib 目錄中的,或者被 -Xbootclasspath 參數(shù)所指定的路徑中的,并且是虛擬機(jī)識(shí)別的(僅按照文件名識(shí)別,如 rt.jar,名字不符合的類(lèi)庫(kù)即使放在 lib 目錄中也不會(huì)被加載)類(lèi)庫(kù)加載到虛擬機(jī)內(nèi)存中。啟動(dòng)類(lèi)加載器無(wú)法被 Java 程序直接引用,用戶在編寫(xiě)自定義類(lèi)加載器時(shí),如果需要把加載請(qǐng)求委派給啟動(dòng)類(lèi)加載器,直接使用 null 代替即可。
  2. 擴(kuò)展類(lèi)加載器(Extension ClassLoader)
    這個(gè)類(lèi)加載器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實(shí)現(xiàn)的。它負(fù)責(zé)將 <JAVA_HOME>/lib/ext 或者被 java.ext.dir 系統(tǒng)變量所指定路徑中的所有類(lèi)庫(kù)加載到內(nèi)存中,開(kāi)發(fā)者可以直接使用擴(kuò)展類(lèi)加載器。
  3. 應(yīng)用程序類(lèi)加載器(Application ClassLoader)
    這個(gè)類(lèi)加載器是由 AppClassLoader(sun.misc.Launcher$AppClassLoader)實(shí)現(xiàn)的。由于這個(gè)類(lèi)加載器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,因此一般稱(chēng)為系統(tǒng)類(lèi)加載器。它負(fù)責(zé)加載用戶類(lèi)路徑(ClassPath)上所指定的類(lèi)庫(kù),開(kāi)發(fā)者可以直接使用這個(gè)類(lèi)加載器,如果應(yīng)用程序中沒(méi)有自定義過(guò)自己的類(lèi)加載器,一般情況下這個(gè)就是程序中默認(rèn)的類(lèi)加載器。

雙親委派模型

每一個(gè)類(lèi)都有一個(gè)對(duì)應(yīng)它的類(lèi)加載器。系統(tǒng)中的 ClassLoder 在協(xié)同工作的時(shí)候會(huì)默認(rèn)使用 雙親委派模型 。

1、在類(lèi)加載的時(shí)候,系統(tǒng)會(huì)首先判斷當(dāng)前類(lèi)是否被加載過(guò)。已經(jīng)被加載的類(lèi)會(huì)直接返回,否則才會(huì)嘗試加載。

2、加載的時(shí)候,首先會(huì)把該請(qǐng)求委派該父類(lèi)加載器的 loadClass() 處理,因此所有的請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類(lèi)加載器 BootstrapClassLoader 中。當(dāng)父類(lèi)加載器無(wú)法處理時(shí),才由自己來(lái)處理。

3、當(dāng)父類(lèi)加載器為null時(shí),會(huì)使用啟動(dòng)類(lèi)加載器 BootstrapClassLoader 作為父類(lèi)加載器。

好處

使得 Java 類(lèi)隨著它的類(lèi)加載器一起具有一種帶有優(yōu)先級(jí)的層次關(guān)系,從而使得基礎(chǔ)類(lèi)得到統(tǒng)一。

例如 java.lang.Object 存放在 rt.jar 中,如果編寫(xiě)另外一個(gè) java.lang.Object 并放到 ClassPath 中,程序可以編譯通過(guò)。

由于雙親委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 優(yōu)先級(jí)更高,這是因?yàn)?rt.jar 中的 Object 使用的是啟動(dòng)類(lèi)加載器,而 ClassPath 中的 Object 使用的是應(yīng)用程序類(lèi)加載器。rt.jar 中的 Object 優(yōu)先級(jí)更高,那么程序中所有的 Object 都是這個(gè) Object。

保證了Java程序的穩(wěn)定運(yùn)行,可以避免類(lèi)的重復(fù)加載(JVM 區(qū)分不同類(lèi)的方式不僅僅根據(jù)類(lèi)名,相同的類(lèi)文件被不同的類(lèi)加載器加載產(chǎn)生的是兩個(gè)不同的類(lèi)),也保證了 Java 的核心 API 不被篡改。

如果沒(méi)有使用雙親委派模型,而是每個(gè)類(lèi)加載器加載自己的話就會(huì)出現(xiàn)一些問(wèn)題,比如我們編寫(xiě)一個(gè)稱(chēng)為 java.lang.Object 類(lèi)的話,那么程序運(yùn)行的時(shí)候,系統(tǒng)就會(huì)出現(xiàn)多個(gè)不同的 Object 類(lèi)。

注意

這個(gè)雙親翻譯的容易讓人誤解,一般理解雙親都是父母,這里的雙親表達(dá)的是“父母一輩”的人,并不是說(shuō)真的有一個(gè) Mother ClassLoader 和一個(gè) Father ClassLoader 。另外,類(lèi)加載器之間的“父子”關(guān)系也不是通過(guò)繼承來(lái)體現(xiàn)的,是由“優(yōu)先級(jí)”來(lái)決定。官方API文檔對(duì)這部分的描述如下:

The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.

 源碼分析

private final ClassLoader parent; 
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先檢查請(qǐng)求的類(lèi)是否已經(jīng)被加載過(guò)
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        //父加載器不為空,調(diào)用父加載器loadClass()方法處理
                        c = parent.loadClass(name, false);
                    } else {
                        //父加載器為空,使用啟動(dòng)類(lèi)加載器 BootstrapClassLoader 加載
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                   //父類(lèi)加載器無(wú)法完成加載請(qǐng)求
                }
                if (c == null) {
                    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;
        }
    }

自定義加載器

除了 BootstrapClassLoader 其他類(lèi)加載器均由 Java 實(shí)現(xiàn)且全部繼承自java.lang.ClassLoader。

如果我們要自定義自己的類(lèi)加載器,很明顯需要繼承 ClassLoader。

示例:自定義一個(gè)NetworkClassLoader,用于加載網(wǎng)絡(luò)上的class文件

package classloader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
/**
 * 加載網(wǎng)絡(luò)class的ClassLoader
 */
public class NetworkClassLoader extends ClassLoader {
	private String rootUrl;
	public NetworkClassLoader(String rootUrl) {
		this.rootUrl = rootUrl;
	}
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		Class clazz = null;//this.findLoadedClass(name); // 父類(lèi)已加載	
		//if (clazz == null) {	//檢查該類(lèi)是否已被加載過(guò)
			byte[] classData = getClassData(name);	//根據(jù)類(lèi)的二進(jìn)制名稱(chēng),獲得該class文件的字節(jié)碼數(shù)組
			if (classData == null) {
				throw new ClassNotFoundException();
			}
			clazz = defineClass(name, classData, 0, classData.length);	//將class的字節(jié)碼數(shù)組轉(zhuǎn)換成Class類(lèi)的實(shí)例
		//} 
		return clazz;
	}
	private byte[] getClassData(String name) {
		InputStream is = null;
		try {
			String path = classNameToPath(name);
			URL url = new URL(path);
			byte[] buff = new byte[1024*4];
			int len = -1;
			is = url.openStream();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			while((len = is.read(buff)) != -1) {
				baos.write(buff,0,len);
			}
			return baos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
			   try {
			      is.close();
			   } catch(IOException e) {
			      e.printStackTrace();
			   }
			}
		}
		return null;
	}
	private String classNameToPath(String name) {
		return rootUrl + "/" + name.replace(".", "/") + ".class";
	}
}

到此這篇關(guān)于Java中JVM的類(lèi)加載器詳解的文章就介紹到這了,更多相關(guān)JVM類(lèi)加載器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java實(shí)現(xiàn)簡(jiǎn)單聊天軟件

    java實(shí)現(xiàn)簡(jiǎn)單聊天軟件

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單的聊天軟件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Java使用Semaphore對(duì)單接口進(jìn)行限流

    Java使用Semaphore對(duì)單接口進(jìn)行限流

    本篇主要講如何使用Semaphore對(duì)單接口進(jìn)行限流,主要有三種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • Java?中的5個(gè)代碼性能提升技巧

    Java?中的5個(gè)代碼性能提升技巧

    這篇文章主要給大家分享了Java的5個(gè)代碼性能提升的技巧,雖然大多數(shù)情況下極致優(yōu)化代碼是沒(méi)有必要的,但是作為一名技術(shù)開(kāi)發(fā)者,我們還是想追求代碼的更小、更快,更強(qiáng)。如果哪天發(fā)現(xiàn)程序的運(yùn)行速度不盡人意,就需要這樣的文章了,需要的朋友可以參考一下
    2021-12-12
  • java實(shí)現(xiàn)Base64加密解密算法

    java實(shí)現(xiàn)Base64加密解密算法

    Base64用來(lái)將非ASCII字符的數(shù)據(jù)轉(zhuǎn)換成ASCII字符的一種方法,這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)Base64加密解密算法,感興趣的小伙伴們可以參考一下
    2016-04-04
  • 將Java的List結(jié)構(gòu)通過(guò)GSON庫(kù)轉(zhuǎn)換為JSON的方法示例

    將Java的List結(jié)構(gòu)通過(guò)GSON庫(kù)轉(zhuǎn)換為JSON的方法示例

    GONS是Google在GitHub上開(kāi)源的Java類(lèi)庫(kù),提供各種Java對(duì)象和JSON格式對(duì)象之間的轉(zhuǎn)換功能,將Java的List結(jié)構(gòu)通過(guò)GSON庫(kù)轉(zhuǎn)換為JSON的方法示例
    2016-06-06
  • spring boot實(shí)現(xiàn)profiles動(dòng)態(tài)切換的示例

    spring boot實(shí)現(xiàn)profiles動(dòng)態(tài)切換的示例

    Spring Boot支持在不同的環(huán)境下使用不同的配置文件,該技術(shù)非常有利于持續(xù)集成,在構(gòu)建項(xiàng)目的時(shí)候只需要使用不同的構(gòu)建命令就可以生成不同運(yùn)行環(huán)境下war包,而不需要手動(dòng)切換配置文件。
    2020-10-10
  • SpringBoot讀取配置優(yōu)先級(jí)順序的方法詳解

    SpringBoot讀取配置優(yōu)先級(jí)順序的方法詳解

    Spring Boot作為一種輕量級(jí)的Java應(yīng)用程序框架,以其開(kāi)箱即用、快速搭建新項(xiàng)目的特性贏得了廣大開(kāi)發(fā)者的青睞,在Spring Boot生態(tài)系統(tǒng)中,配置屬性可以從各種來(lái)源獲取,本文將深入探討Spring Boot加載外部配置屬性的優(yōu)先級(jí)規(guī)則,需要的朋友可以參考下
    2024-05-05
  • 詳解Java中final的用法

    詳解Java中final的用法

    本文主要介紹了Java中final的使用方法,final是java的關(guān)鍵字,本文就詳細(xì)說(shuō)明一下它的使用方法,需要的朋友可以參考下
    2015-08-08
  • 解決mybatis批量更新(update foreach)失敗的問(wèn)題

    解決mybatis批量更新(update foreach)失敗的問(wèn)題

    這篇文章主要介紹了解決mybatis批量更新(update foreach)失敗的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • Spring Cloud Gateway實(shí)現(xiàn)灰度發(fā)布方案

    Spring Cloud Gateway實(shí)現(xiàn)灰度發(fā)布方案

    灰度發(fā)布是在微服務(wù)中的表現(xiàn)為同一服務(wù)同時(shí)上線不同版本,讓一部分用戶使用新版本來(lái)驗(yàn)證新特性,如果驗(yàn)證沒(méi)有問(wèn)題,則將所有用戶都遷移到新版本上,本文就來(lái)介紹一下如何實(shí)現(xiàn),感興趣的可以了解一下
    2023-12-12

最新評(píng)論