偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

三分鐘帶你搞懂雙親委派模型!

開(kāi)發(fā) 前端
雙親委派,指的是在接受類(lèi)加載請(qǐng)求時(shí),會(huì)讓父類(lèi)加載器試圖加載該類(lèi),只有在父類(lèi)加載器無(wú)法加載該類(lèi)或者沒(méi)有父類(lèi)時(shí),才嘗試從自己的類(lèi)路徑中加載該類(lèi)。

什么是雙親委派?

在 Java 虛擬機(jī)中,任何一個(gè)類(lèi)由加載它的類(lèi)加載器和這個(gè)類(lèi)一同來(lái)確立其唯一性。

也就是說(shuō),JVM 對(duì)類(lèi)的唯一標(biāo)識(shí),可以簡(jiǎn)單的理解為由ClassLoader id + PackageName + ClassName組成,因此在一個(gè)運(yùn)行程序中有可能存在兩個(gè)包名和類(lèi)名完全一致的類(lèi),但是如果這兩個(gè)類(lèi)不是由一個(gè) ClassLoader 加載,會(huì)被視為兩個(gè)不同的類(lèi),此時(shí)就無(wú)法將一個(gè)類(lèi)的實(shí)例強(qiáng)轉(zhuǎn)為另外一個(gè)類(lèi),這就是類(lèi)加載器的隔離性。

為了解決類(lèi)加載器的隔離問(wèn)題,JVM 引入了雙親委派模型。

雙親委派模式,可以用一句話(huà)來(lái)說(shuō)表達(dá):任何一個(gè)類(lèi)加載器在接到一個(gè)類(lèi)的加載請(qǐng)求時(shí),都會(huì)先讓其父類(lèi)進(jìn)行加載,只有父類(lèi)無(wú)法加載(或者沒(méi)有父類(lèi))的情況下,才嘗試自己加載。

大致流程圖如下:

圖片圖片

使用雙親委派模式,可以保證,每一個(gè)類(lèi)只會(huì)有一個(gè)類(lèi)加載器。例如 Java 最基礎(chǔ)的 Object 類(lèi),它存放在 rt.jar 之中,這是 Bootstrap 的職責(zé)范圍,當(dāng)向上委派到 Bootstrap 時(shí)就會(huì)被加載。

但如果沒(méi)有使用雙親委派模式,可以任由自定義加載器進(jìn)行加載的話(huà),Java 這些核心類(lèi)的 API 就會(huì)被隨意篡改,無(wú)法做到一致性加載效果。

JDK 中ClassLoader.loadClass()類(lèi)加載器中的加載類(lèi)的方法,部分核心源碼如下:

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
{
    // 1.首先要保證線(xiàn)程安全
    synchronized (getClassLoadingLock(name)) {
        // 2.先判斷這個(gè)類(lèi)是否被加載過(guò),如果加載過(guò),直接跳過(guò)
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                // 3.有父類(lèi),優(yōu)先交給父類(lèi)嘗試加載;如果為空,使用BootstrapClassLoader類(lèi)加載器
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // 父類(lèi)加載失敗,這里捕獲異常,但不需要做任何處理
            }

            // 4.沒(méi)有父類(lèi),或者父類(lèi)無(wú)法加載,嘗試自己加載
            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;
    }
}

如何自定義類(lèi)加載器?

針對(duì)某些特定場(chǎng)景,比如通過(guò)網(wǎng)絡(luò)來(lái)傳輸 Java 類(lèi)的字節(jié)碼文件,為保證安全性,這些字節(jié)碼經(jīng)過(guò)了加密處理,這時(shí)系統(tǒng)提供的類(lèi)加載器就無(wú)法對(duì)其進(jìn)行加載,此時(shí)我們可以自定義一個(gè)類(lèi)加載器來(lái)完成文件的加載。

自定義類(lèi)加載器也需要繼承ClassLoader類(lèi),簡(jiǎn)單示例如下:

public class CustomClassLoader extends ClassLoader {

    private String classPath;

    public CustomClassLoader(String classPath) {
        this.classPath = classPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            byte[] data = loadClassData(name);
            if (data == null) {
                throw new ClassNotFoundException();
            }
            return defineClass(name, data, 0, data.length);
        }
        return null;
    }

    protected byte[] loadClassData(String name) {
        try {
            // package -> file folder
            name = name.replace(".", "http://");
            FileInputStream fis = new FileInputStream(new File(classPath + "http://" + name + ".class"));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len = -1;
            byte[] b = new byte[2048];
            while ((len = fis.read(b)) != -1) {
                baos.write(b, 0, len);
            }
            fis.close();
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

相關(guān)的測(cè)試類(lèi)如下:

package com.example;

public class ClassLoaderTest {

    public static void main(String[] args) {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        System.out.println("current loader:" +  loader);
    }
}

將ClassLoaderTest.java源文件放在指定目錄下,并通過(guò)javac命令編譯成ClassLoaderTest.class,最后進(jìn)行測(cè)試。

public class CustomClassLoaderTest {

    public static void main(String[] args) throws Exception {
        String classPath = "/Downloads";
        CustomClassLoader customClassLoader = new CustomClassLoader(classPath);
        Class<?> testClass = customClassLoader.loadClass("com.example.ClassLoaderTest");
        Object obj = testClass.newInstance();
        System.out.println(obj.getClass().getClassLoader());
    }
}

輸出結(jié)果:

com.example.CustomClassLoader@60e53b93

在實(shí)際使用過(guò)程中,最好不要重寫(xiě)loadClass方法,避免破壞雙親委派模型。

小結(jié)

雙親委派,指的是在接受類(lèi)加載請(qǐng)求時(shí),會(huì)讓父類(lèi)加載器試圖加載該類(lèi),只有在父類(lèi)加載器無(wú)法加載該類(lèi)或者沒(méi)有父類(lèi)時(shí),才嘗試從自己的類(lèi)路徑中加載該類(lèi)。

其次,針對(duì)某些場(chǎng)景,如果要實(shí)現(xiàn)類(lèi)的隔離,可以自定義類(lèi)加載器來(lái)實(shí)現(xiàn)特定類(lèi)的加載。

責(zé)任編輯:武曉燕 來(lái)源: Java極客技術(shù)
相關(guān)推薦

2024-01-16 07:46:14

FutureTask接口用法

2024-01-12 07:38:38

AQS原理JUC

2020-06-30 10:45:28

Web開(kāi)發(fā)工具

2021-04-20 13:59:37

云計(jì)算

2024-08-30 08:50:00

2022-02-17 09:24:11

TypeScript編程語(yǔ)言javaScrip

2025-02-24 10:40:55

2023-12-04 18:13:03

GPU編程

2020-03-08 16:45:58

數(shù)據(jù)挖掘學(xué)習(xí)數(shù)據(jù)量

2017-01-18 15:38:20

語(yǔ)言

2024-09-13 08:49:45

2021-02-03 14:31:53

人工智能人臉識(shí)別

2023-01-31 08:24:55

HashMap死循環(huán)

2024-06-06 08:50:43

2024-02-22 07:37:37

對(duì)象JVM內(nèi)存

2022-03-26 09:06:40

ActorCSP模型

2023-12-23 18:04:40

服務(wù)Eureka工具

2024-12-18 10:24:59

代理技術(shù)JDK動(dòng)態(tài)代理

2009-11-09 12:55:43

WCF事務(wù)

2024-05-16 11:13:16

Helm工具release
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)