中文字幕在线一区二区在线,久久久精品免费观看国产,无码日日模日日碰夜夜爽,天堂av在线最新版在线,日韩美精品无码一本二本三本,麻豆精品三级国产国语,精品无码AⅤ片,国产区在线观看视频

      最新java classloader詳解

      時間:2024-08-11 14:37:44 JAVA認證 我要投稿
      • 相關推薦

      2016最新java classloader詳解

        Classloader 類加載器,用來加載Java類到 Java 虛擬機中的一種加載器。那么Classloader 類有什么原理呢?下面跟yjbys小編一起來學習一下!

        JAVA啟動后,是經過JVM各級ClassLoader來加載各個類到內存。為了更加了解加載過程,我通過分析和寫了一個簡單的ClassLoader來粗淺的分析它的原理。

        JVM的ClassLoader分三層,分別為Bootstrap ClassLoader,Extension ClassLoader,System ClassLoader,他們不是類繼承的父子關系,是邏輯上的上下級關系。

        Bootstrap ClassLoader是啟動類加載器,它是用C++編寫的,從%jre%/lib目錄中加載類,或者運行時用-Xbootclasspath指定目錄來加載。

        Extension ClassLoader是擴展類加載器,從%jre%/lib/ext目錄加載類,或者運行時用-Djava.ext.dirs制定目錄來加載。

        System ClassLoader,系統(tǒng)類加載器,它會從系統(tǒng)環(huán)境變量配置的classpath來查找路徑,環(huán)境變量里的.表示當前目錄,是通過運行時-classpath或-Djava.class.path指定的目錄來加載類。

        一般自定義的Class Loader可以從java.lang.ClassLoader繼承,不同classloader加載相同的類,他們在內存也不是相等的,即它們不能互相轉換,會直接拋異常。java.lang.ClassLoader的核心加載方法是loadClass方法,如:

        protected synchronized Class loadClass(String name, boolean resolve)

        throws ClassNotFoundException

        {

        // First, check if the class has already been loaded

        Class c = findLoadedClass(name);

        if (c == null) {

        try {

        if (parent != null) {

        c = parent.loadClass(name, false);

        } else {

        c = findBootstrapClass0(name);

        }

        } catch (ClassNotFoundException e) {

        // If still not found, then invoke findClass in order

        // to find the class.

        c = findClass(name);

        }

        }

        if (resolve) {

        resolveClass(c);

        }

        return c;

        }

        通過上面加載過程,我們能知道JVM默認是雙親委托加載機制,即首先判斷緩存是否有已加載的類,如果緩存沒有,但存在父加載器,則讓父加載器加載,如果不存在父加載器,則讓Bootstrap ClassLoader去加載,如果父類加載失敗,則調用本地的findClass方法去加載。

        可以通過下面三條語句,輸入現(xiàn)在加載的各個classloader的加載路徑:

        System.out.println("sun.boot.class.path:" + System.getProperty("sun.boot.class.path"));

        System.out.println("java.ext.dirs:" + System.getProperty("java.ext.dirs"));

        System.out.println("java.class.path:" +System.getProperty("java.class.path"));

        ClassLoader cl = Thread.currentThread().getContextClassLoader();//ClassLoader.getSystemClassLoader()

        System.out.println("getContextClassLoader:" +cl.toString());

        System.out.println("getContextClassLoader.parent:" +cl.getParent().toString());

        System.out.println("getContextClassLoader.parent2:" +cl.getParent().getParent());

        輸出結果為:

        sun.boot.class.path:C:\Program Files\Java\jre7\lib\resources.jar;C:\Program Files\Java\jre7\lib\rt.jar;C:\Program Files\Java\jre7\lib\sunrsasign.jar;C:\Program Files\Java\jre7\lib\jsse.jar;C:\Program Files\Java\jre7\lib\jce.jar;C:\Program Files\Java\jre7\lib\charsets.jar;C:\Program Files\Java\jre7\classes

        java.ext.dirs:C:\Program Files\Java\jre7\lib\ext;C:\Windows\Sun\Java\lib\ext

        java.class.path:E:\MyProjects\workspace\TestConsole\bin

        getContextClassLoader:sun.misc.Launcher$AppClassLoader@19dbc3b

        getContextClassLoader.parent:sun.misc.Launcher$ExtClassLoader@b103dd

        getContextClassLoader.parent2:null

        從上面的運行結果可以看出邏輯上的層級繼承關系。雙親委托機制的作用是防止系統(tǒng)jar包被本地替換,因為查找方法過程都是從最底層開始查找。 因此,一般我們自定義的classloader都需要采用這種機制,我們只需要繼承java.lang.ClassLoader實現(xiàn)findclass即可,如果需要更多控制,自定義的classloader就需要重寫loadClass方法了,比如tomcat的加載過程,這個比較復雜,可以通過其他文檔資料查看相關介紹。

        各個ClassLoader加載相同的類后,他們是不互等的,這個當涉及多個ClassLoader,并且有通過當前線程上線文獲取ClassLoader后轉換特別需要注意,可以通過線程的setContextClassLoader設置一個ClassLoader線程上下文,然后再通過Thread.currentThread().getContextClassLoader()獲取當前線程保存的Classloader。但是自定義的類文件,放到Bootstrap ClassLoader加載目錄,是不會被Bootstrap ClassLoader加載的,因為作為啟動類加載器,它不會加載自己不熟悉的jar包的,并且類文件必須打包成jar包放到加載器加載的根目錄,才可能被擴展類加載器所加載。

        下面我自定義一個簡單的classloader:

        public class TestClassLoader extends ClassLoader {

        //定義文件所在目錄

        private static final String DEAFAULTDIR="E:\\MyProjects\\workspace\\TestConsole\\bin\\";

        public Class findClass(String name) throws ClassNotFoundException {

        byte[] b = null;

        try {

        b = loadClassData(GetClassName(name));

        } catch (Exception e) {

        e.printStackTrace();

        }

        return defineClass(name, b, 0, b.length);

        }

        @Override

        protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {

        if(name.startsWith("java.")){try {

        return super.loadClass(name, false);

        } catch (ClassNotFoundException e) {

        e.printStackTrace();

        }

        }

        byte[] b = null;

        try {

        b = loadClassData(GetClassName(name));

        } catch (Exception e) {

        e.printStackTrace();

        }

        return defineClass(name, b, 0, b.length);

        }

        private byte[] loadClassData(String filepath) throws Exception {

        int n =0;

        BufferedInputStream br = new BufferedInputStream(

        new FileInputStream(

        new File(filepath)));

        ByteArrayOutputStream bos= new ByteArrayOutputStream();

        while((n=br.read())!=-1){

        bos.write(n);

        }

        br.close();

        return bos.toByteArray();

        }

        public static String GetClassName(String name){

        return DEAFAULTDIR+name.replace('.','/')+".class";

        }

        }

        這個自定義的ClassLoader重寫了loadclass方法,但不用默認的雙親委托,比如java.lang包下面的都無法解析,這里我簡單的判斷如果是java.開始的包則用父類去解析,能簡單的滿足雙親委托機制,但是其他相關非系統(tǒng)類加載也沒有用父類加載了。

        測試代碼如:

        TestClassLoader liuloader = new TestClassLoader();

        Myrunner runner = new Myrunner();

        runner.setContextClassLoader(liuloader);

        runner.start();

        Myrunner是我自定義繼承自Thread的線程,通過設置線程上下文的classloader后,線程內部測試代碼如:

        ClassLoader cl1 = Thread.currentThread().getContextClassLoader();

        System.out.println(cl1);

        它將會輸出:

        com.liu.ClassLoader.TestClassLoader@347cdb,說明已經為當前線程上下文設置了自定義的Classloader了,如果這個線程內部通過這個classloader加載一個類,再轉換成當前的類,如代碼:

        Class c = cl1.loadClass("com.liu.ClassLoader.TestLoader2"); TestLoader2 tloader = (TestLoader2)c.newInstance();

        則為拋java.lang.ClassCastException異常: com.liu.ClassLoader.TestLoader2 cannot be cast to com.liu.ClassLoader.TestLoader2。

        因為cl1當前是 TestClassLoader加載的,而這個TestLoader2的類還是默認由AppClassLoader加載,因此它們不能隱式轉換,Classloader加載相同的類,內存認為它們是沒有關系的對象。

        如果把我自定義的TestClassLoader里的LoadClass方法去掉,則采用了雙親委托機制,這樣我們除了指定的類以外,其他都會優(yōu)先用父類來加載。這樣可以解決剛才的java.lang.ClassCastException異常問題,為加載的對象建立一個抽象父類,自定義的Classloader負責加載子類,父類統(tǒng)一交給AppClassLoader或父加載器來加載,這樣線程內部可以使用類試:

        Class c = cl1.loadClass("com.liu.ClassLoader.TestLoader2");

        BaseTest tloader = (BaseTest)c.newInstance();

        BaseTest是TestLoader2的父類,因為BaseTest都是AppClassLoader或父加載器加載的,因此可以達到成功隱式轉換的目的。

        對于Tomcat等幾個處理的Classloader都是自定義并重寫了loadclass方法,內部會更復雜處理。

      【最新java classloader詳解】相關文章:

      Java ClassLoader原理深入講解03-04

      Java ClassLoader原理詳細分析201603-04

      Java基礎知識詳解12-07

      Java文件解壓縮實例詳解201603-04

      最新連詞的種類詳解01-04

      最新韓國留學申請種類詳解03-05

      最新加拿大留學傳媒專業(yè)詳解03-07

      科目一考試最新技巧口訣詳解02-27

      2016最新Java認證筆試題及答案01-21

      主站蜘蛛池模板: 福利网在线| 国产91第一页| av永远在线免费观看| 获嘉县| 久国产精品久久精品国产四虎| 最新版av天堂熟女免费播放| 肥西县| 日韩在线视频不卡一区二区三区| 日本高清一区二区三区视频| 亚洲青青草视频免费观看| 安远县| 欧美人与动牲交片免费| 在线观看一区二区女同| 成年毛片18成年毛片| 国产麻豆放荡av激情演绎| 亚洲精品国产主播一区二区| 江川县| 亚洲av男人的在线的天堂| 午夜无码片在线观看影院y| 一本色道久久综合亚洲精品不卡| 中文字幕日韩精品美一区二区三区 | 黔南| 美女裸体无遮挡黄污网站| 亚洲国产剧情在线精品视| 9l久久午夜精品一区二区| 成年毛片18成年毛片| 青青草一级视频在线观看| 亚洲AV秘 无套一区二区三区| 日韩av一区二区毛片| 无码熟妇人妻AV不卡| 通州市| 国产激情视频在线| 亚洲国产一区久久yourpan| 红桥区| 昌黎县| 中国少妇久久一区二区| 国产一区中文字幕手机在线| 国产精品国产三级国产av创| 91精品国产91久久久无码色戒| 国产一区二区三区av免费观看| 中文字幕亚洲好看有码|