最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解jvm雙親委派機(jī)制

 更新時(shí)間:2022年11月08日 08:28:39   作者:尋找的路上  
雙親委派機(jī)制保證了核心類的安全,確保不會(huì)被修改,也保證了不會(huì)加載到重復(fù)的字節(jié)碼文件,這篇文章主要介紹了jvm雙親委派機(jī)制詳解,需要的朋友可以參考下

雙親委派機(jī)制

?記錄一下JVM的雙親委派機(jī)制學(xué)習(xí)記錄。

類加載器種類

?當(dāng)我們運(yùn)行某一個(gè)java類的main方法時(shí),首先需要由java虛擬機(jī)的類加載器將我們要執(zhí)行的main方法所在的class文件加載到j(luò)vm中,這里提到的類加載器大概有4種:

引導(dǎo)類加載器:負(fù)責(zé)加載支撐JVM運(yùn)行的位于JRE的lib目錄下的核心類庫(kù),比如rt.jar、charsets.jar等
擴(kuò)展類加載器:負(fù)責(zé)加載支撐JVM運(yùn)行的位于JRE的lib目錄下的ext擴(kuò)展目錄中的JAR類包
應(yīng)用程序類加載器:負(fù)責(zé)加載ClassPath路徑下的類包,主要就是加載你自己寫的那些類
自定義加載器:負(fù)責(zé)加載用戶自定義路徑下的類包。

?每個(gè)類加載器加載的包路徑都是不同的,有各自的職責(zé)。通過一下示例,可以看出每個(gè)類加載器加載的路徑:

public class TestJDKClassLoader {

    public static void main(String[] args) {
        System.out.println(String.class.getClassLoader());
        System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName());
        System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName());
        System.out.println();
        ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
        ClassLoader extClassloader = appClassLoader.getParent();
        ClassLoader bootstrapLoader = extClassloader.getParent();
        System.out.println("the bootstrapLoader : " + bootstrapLoader);
        System.out.println("the extClassloader : " + extClassloader);
        System.out.println("the appClassLoader : " + appClassLoader);

        System.out.println();
        System.out.println("bootstrapLoader加載以下文件:");
        URL[] urls = Launcher.getBootstrapClassPath().getURLs();
        for (int i = 0; i < urls.length; i++) {
            System.out.println(urls[i]);
        }

        System.out.println();
        System.out.println("extClassloader加載以下文件:");
        System.out.println(System.getProperty("java.ext.dirs"));
        System.out.println();
        System.out.println("appClassLoader加載以下文件:");
        System.out.println(System.getProperty("java.class.path"));
    }
}

// 運(yùn)行結(jié)果:
null
sun.misc.Launcher$ExtClassLoader
sun.misc.Launcher$AppClassLoader

the bootstrapLoader : null
the extClassloader : sun.misc.Launcher$ExtClassLoader@330bedb4
the appClassLoader : sun.misc.Launcher$AppClassLoader@14dad5dc

bootstrapLoader加載以下文件:
file:/D:/ProgramFiles/jdk1.8.0_45_64bit/jre/lib/resources.jar
file:/D:/ProgramFiles/jdk1.8.0_45_64bit/jre/lib/rt.jar
file:/D:/ProgramFiles/jdk1.8.0_45_64bit/jre/lib/sunrsasign.jar
file:/D:/ProgramFiles/jdk1.8.0_45_64bit/jre/lib/jsse.jar
file:/D:/ProgramFiles/jdk1.8.0_45_64bit/jre/lib/jce.jar
file:/D:/ProgramFiles/jdk1.8.0_45_64bit/jre/lib/charsets.jar
file:/D:/ProgramFiles/jdk1.8.0_45_64bit/jre/lib/jfr.jar
file:/D:/ProgramFiles/jdk1.8.0_45_64bit/jre/classes

extClassloader加載以下文件:
D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext

appClassLoader加載以下文件:
D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\charsets.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\deploy.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\access-bridge-64.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\cldrdata.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\dnsns.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\jaccess.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\jfxrt.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\localedata.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\nashorn.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\sunec.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\sunjce_provider.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\sunmscapi.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\sunpkcs11.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\ext\zipfs.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\javaws.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\jce.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\jfr.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\jfxswt.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\jsse.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\management-agent.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\plugin.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\resources.jar;D:\ProgramFiles\jdk1.8.0_45_64bit\jre\lib\rt.jar;D:\Files\learn\tuling\jvm-demo\target\classes;D:\ProgramFiles\ideaIU-2021.3.3.win\lib\idea_rt.jar

Process finished with exit code 0

appClassLoader雖然打印的內(nèi)容雖然很多,但它只需要加載target目錄下的文件。

雙親委派機(jī)制

?雖然基本只有4種類加載器,但這4種類加載器之間是存在一定的關(guān)聯(lián)關(guān)系的。如下圖:

?加載某個(gè)類時(shí)會(huì)先委托給父加載器尋找目標(biāo)類,找不到再委托上層父類加載器加載,所有的父類加載器在自己的加載類路徑下都找不到目標(biāo)類,則在自己的類加載路徑中尋找并載入目標(biāo)類。

?比如上面的TestJDKClassLoader,首先會(huì)委托應(yīng)用程序類加載,應(yīng)用程序類加載器則委托擴(kuò)展類加載器加載,擴(kuò)展類加載器則委托引導(dǎo)類加載器加載,引導(dǎo)類加載器在它的類加載路徑下找不到TestJDKClassLoader.class文件,則向下委托擴(kuò)展類加載器加載,擴(kuò)展類加載器加載不到則委托應(yīng)用程序類加載器自己加載,于是應(yīng)用程序類加載器在target目錄下找到并載入了TestJDKClassLoader.class文件。

我們來看下應(yīng)用程序類加載器AppClassLoader加載類的雙親委派機(jī)制源碼,AppClassLoader的loadClass方法最終會(huì)調(diào)用其父類ClassLoader的loadClass方法,該方法的大體邏輯如下:

我們來看下應(yīng)用程序類加載器AppClassLoader加載類的雙親委派機(jī)制源碼,AppClassLoader的loadClass方法最終會(huì)調(diào)用其父類ClassLoader的loadClass方法,該方法的大體邏輯如下:

我們來看下應(yīng)用程序類加載器AppClassLoader加載類的雙親委派機(jī)制源碼,AppClassLoader的loadClass方法最終會(huì)調(diào)用其父類ClassLoader的loadClass方法,該方法的大體邏輯如下:

1.首先,檢查一下指定名稱的類是否已經(jīng)加載過,如果加載過了,就不需要再加載,直接

返回。

2.如果此類沒有加載過,那么,再判斷一下是否有父加載器;如果有父加載器,則由父加

載器加載(即調(diào)用parent.loadClass(name, false);).或者是調(diào)用bootstrap類加載器來加

載。

3.如果父加載器及bootstrap類加載器都沒有找到指定的類,那么調(diào)用當(dāng)前類加載器的

findClass方法來完成類加載。

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        // 檢查當(dāng)前類加載器是否已經(jīng)找到
        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;
    }
}

為什么要設(shè)計(jì)雙親委派機(jī)制?

沙箱安全機(jī)制:自己寫的java.lang.String.class類不會(huì)被加載,這樣便可以防止核心
API庫(kù)被隨意篡改
避免類的重復(fù)加載:當(dāng)父親已經(jīng)加載了該類時(shí),就沒有必要子ClassLoader再加載一
次,保證被加載類的唯一性

例子:比如我們自己新建了一個(gè)java.lang.String類,我們看能不能加載成功。

package java.lang;

public class String {

    public static void main(String[] args) {
        System.out.println("============自己的類加載器====");
    }
}

// 執(zhí)行結(jié)果
錯(cuò)誤: 在類 java.lang.String 中找不到 main 方法, 請(qǐng)將 main 方法定義為:
   public static void main(String[] args)
否則 JavaFX 應(yīng)用程序類必須擴(kuò)展javafx.application.Application

自定義類加載器

自定義類加載器只需要繼承 java.lang.ClassLoader 類,該類有兩個(gè)核心方法,一個(gè)是loadClass(String, boolean),實(shí)現(xiàn)了雙親委派機(jī)制,還有一個(gè)方法是findClass,默認(rèn)實(shí)現(xiàn)是空方法,所以我們自定義類加載器主要是重寫findClass方法。

public class MyClassLoaderTest {
    static class MyClassLoader extends ClassLoader {
        private String classPath;

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

        private byte[] loadByte(String name) throws Exception {
            name = name.replaceAll("\\.", "/");
            FileInputStream fis = new FileInputStream(classPath + "/" + name
                + ".class");
            int len = fis.available();
            byte[] data = new byte[len];
            fis.read(data);
            fis.close();
            return data;
        }

        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByte(name);
                //defineClass將一個(gè)字節(jié)數(shù)組轉(zhuǎn)為Class對(duì)象,這個(gè)字節(jié)數(shù)組是class文件讀取后最終的字節(jié)數(shù)組。
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        //初始化自定義類加載器,會(huì)先初始化父類ClassLoader,其中會(huì)把自定義類加載器的父加載器設(shè)置為應(yīng)用程序類加載器AppClassLoader
        MyClassLoader classLoader = new MyClassLoader("D:/test");
        //D盤創(chuàng)建 test/com/hyz/jvm 幾級(jí)目錄,將User類的復(fù)制類User1.class丟入該目錄
        Class clazz = classLoader.loadClass("com.hyz.jvm.User1");
//        Class clazz = classLoader.loadClass("java.lang.String");
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("hello", null);
        method.invoke(obj, null);

        System.out.println(clazz.getClassLoader().getClass().getName());
    }
}

打破雙親委派機(jī)制

?假如我們的target下有一個(gè)User類,但是我們的程序代碼中需要去讀取D:/test/com/hyz/jvm/User.class類,根據(jù)雙親委派機(jī)制,肯定是會(huì)加載到target下的User類的,要如何才能加載到D:/test下的User類呢?

?那意味著我們需要去打破雙親委派機(jī)制??碅ppClassLoader的類加載邏輯,主要邏輯在父類ClassLoader.loadClass()方法中,我們只需要在自定義的類加載器中重寫該方法即可。主要修改邏輯:如果類型是com.hyz.jvm開頭的類,則從自定義類加載器中去讀取,否則委托給上層類加載器加載。

/**
 * 32 * 重寫類加載方法,實(shí)現(xiàn)自己的加載邏輯,不委派給雙親加載
 * 33 * @param name
 * 34 * @param resolve
 * 35 * @return
 * 36 * @throws ClassNotFoundException
 * 37
 */
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) {
            // If still not found, then invoke findClass in order
            // to find the class.
            long t1 = System.nanoTime();
            if (!name.startsWith("com.hyz.jvm")) {
                c = this.getParent().loadClass(name);
            } else {
                c = findClass(name);
            }
            // this is the defining class loader; record the stats
            sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
            sun.misc.PerfCounter.getFindClasses().increment();
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

?應(yīng)用到打破雙親委派機(jī)制的實(shí)際應(yīng)用場(chǎng)景是在Tomcat加載war包。比如war1用的是spring4版本,war2用的是spring5版本,那就意味著加載著2個(gè)war包不能用同一個(gè)類加載器實(shí)例,需要各自指定一個(gè)自定義的類加載器實(shí)例,各自去加載所需的spring版本庫(kù)文件。

總結(jié):雙親委派機(jī)制保證了核心類的安全,確保不會(huì)被修改,也保證了不會(huì)加載到重復(fù)的字節(jié)碼文件。

到此這篇關(guān)于jvm雙親委派機(jī)制詳解的文章就介紹到這了,更多相關(guān)jvm雙親委派機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java多線程Future和Callable類示例分享

    java多線程Future和Callable類示例分享

    JAVA多線程實(shí)現(xiàn)方式主要有三種:繼承Thread類、實(shí)現(xiàn)Runnable接口、使用ExecutorService、Callable、Future實(shí)現(xiàn)有返回結(jié)果的多線程。其中前兩種方式線程執(zhí)行完后都沒有返回值,只有最后一種是帶返回值的。今天我們就來研究下Future和Callable的實(shí)現(xiàn)方法
    2016-01-01
  • Mybatis模糊查詢和動(dòng)態(tài)sql語句的用法

    Mybatis模糊查詢和動(dòng)態(tài)sql語句的用法

    今天小編就為大家分享一篇關(guān)于Mybatis模糊查詢和動(dòng)態(tài)sql語句的用法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • java循環(huán)刪除List元素報(bào)錯(cuò)的原因分析與解決

    java循環(huán)刪除List元素報(bào)錯(cuò)的原因分析與解決

    大家在工作中應(yīng)該都會(huì)遇到從List集合中刪除某一個(gè)或多個(gè)元素的業(yè)務(wù)場(chǎng)景,相信大家都會(huì)避開在循環(huán)里面刪除元素,使用其他方式處理,這是為什么呢,下面小編就來和大家詳細(xì)聊聊
    2023-11-11
  • Spring Boot如何通過CORS處理跨域問題

    Spring Boot如何通過CORS處理跨域問題

    這篇文章主要介紹了Spring Boot如何通過CORS處理跨域問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • java實(shí)現(xiàn)html轉(zhuǎn)pdf方法步驟

    java實(shí)現(xiàn)html轉(zhuǎn)pdf方法步驟

    這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)html轉(zhuǎn)pdf方法的相關(guān)資料,要將HTML轉(zhuǎn)換成PDF,我們需要借助Java中的第三方庫(kù),文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • Java實(shí)現(xiàn)棧和隊(duì)列面試題

    Java實(shí)現(xiàn)棧和隊(duì)列面試題

    這篇文章主要介紹了Java實(shí)現(xiàn)棧和隊(duì)列的面試題,每個(gè)例題代碼實(shí)現(xiàn)非常詳細(xì),每一個(gè)方法講解也很到位,特別適合參加Java面試的朋友閱讀。
    2015-09-09
  • Maven繼承與聚合詳解及作用介紹

    Maven繼承與聚合詳解及作用介紹

    繼承關(guān)系中,分為父模塊與子模塊,父模塊也被稱為 parent 模塊,子模塊會(huì)繼承父模塊的依賴,父模塊中也可以設(shè)置依賴管理器,供子模塊選擇是否需要某些依賴
    2022-08-08
  • 詳談Springfox與swagger的整合使用

    詳談Springfox與swagger的整合使用

    下面小編就為大家?guī)硪黄斦凷pringfox與swagger的整合使用。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • SpringBoot項(xiàng)目整合mybatis的方法步驟與實(shí)例

    SpringBoot項(xiàng)目整合mybatis的方法步驟與實(shí)例

    今天小編就為大家分享一篇關(guān)于SpringBoot項(xiàng)目整合mybatis的方法步驟與實(shí)例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • spring boot使用thymeleaf模板的方法詳解

    spring boot使用thymeleaf模板的方法詳解

    thymeleaf 是新一代的模板引擎,在spring4.0中推薦使用thymeleaf來做前端模版引擎。下面這篇文章主要給大家介紹了關(guān)于spring boot使用thymeleaf模板的方法,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面來一起看看吧。
    2017-07-07

最新評(píng)論

平安县| 广宗县| 油尖旺区| 大方县| 商河县| 宁明县| 华坪县| 迁安市| 昌吉市| 陇西县| 洞头县| 吉林市| 金溪县| 清远市| 浦北县| 全椒县| 杭州市| 山东| 阳城县| 桦川县| 广河县| 革吉县| 昌宁县| 兰溪市| 宜都市| 瑞丽市| 紫云| 芦溪县| 泸溪县| 鄱阳县| 黄骅市| 滁州市| 德安县| 泰州市| 陇西县| 达日县| 建水县| 凉城县| 木里| 乌苏市| 泸州市|