android classloader雙親託付模式

來源:互聯網
上載者:User

標籤:fine   依賴   類型   protected   file   環境   注意   art   cep   

概述

ClassLoader的雙親託付模式:classloader 按層級分為三個層級:最上級 : bootstrap classLoader(根類載入器) ; 中間級:extension classLoader (擴充類載入器) 最低級 app classLoader(應用類載入器)。

根(Bootstrap)類載入器:該載入器沒有父載入器。它負責載入虛擬機器的核心類庫,如java.lang.*等。比如java.lang.Object就是由根類載入器載入的。根類載入器從系統屬性sun.boot.class.path所指定的檔案夾中載入類庫。

根類載入器的實現依賴於底層作業系統。屬於虛擬機器的實現的一部分,它並沒有繼承java.lang.ClassLoader類。

擴充(Extension)類載入器:它的父載入器為根類載入器。它從java.ext.dirs系統屬性所指定的檔案夾中載入類庫,或者從JDK的安裝資料夾的jre/lib/ext子檔案夾(擴充檔案夾)下載入類庫,假設把使用者建立的JAR檔案放在這個檔案夾下,也會自己主動由擴充類載入器載入。擴充類載入器是純Java類,是java.lang.ClassLoader類的子類。

系統(System)類載入器:也稱為應用類載入器。它的父載入器為擴充類載入器。

它從環境變數classpath或者系統屬性java.class.path所指定的檔案夾中載入類,它是使用者自己定義的類載入器的預設父載入器。

系統類別載入器是純Java類。是java.lang.ClassLoader類的子類。


父子載入器並不是繼承關係。也就是說子載入器不一定是繼承了父載入器。

對於Java來說,java 虛擬機器要將被用到的java類檔案通過classLoader 載入到JVM記憶體中。而這個classloader就是bootstrap classloader。而對於APP而言,首先請求app 級來載入,繼而請求extension classLoader,最後啟動bootstrap classLoader 。

自己定義ClassLoader

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhbmd6aGlob25nOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="這裡寫圖片描寫敘述" title="">

public class MyClassLoader extends ClassLoader {    //類載入器名稱    private String name;    //載入類的路徑    private String path = "D:/";    private final String fileType = ".class";    public MyClassLoader(String name){        //讓系統類別載入器成為該 類載入器的父載入器        super();        this.name = name;    }    public MyClassLoader(ClassLoader parent, String name){        //顯示指定該類載入器的父載入器        super(parent);        this.name = name;    }    public String getPath() {        return path;    }    public void setPath(String path) {        this.path = path;    }    @Override    public String toString() {        return this.name;    }    private byte[] loaderClassData(String name){        InputStream is = null;        byte[] data = null;        ByteArrayOutputStream baos = new ByteArrayOutputStream();        this.name = this.name.replace(".", "/");        try {            is = new FileInputStream(new File(path + name + fileType));            int c = 0;            while(-1 != (c = is.read())){                baos.write(c);            }            data = baos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        } finally{            try {                is.close();                baos.close();            } catch (IOException e) {                e.printStackTrace();            }        }        return data;    }    @Override    public Class<?

> findClass(String name){ byte[] data = loaderClassData(name); return this.defineClass(name, data, 0, data.length); } public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { //loader1的父載入器為系統類別載入器 MyClassLoader loader1 = new MyClassLoader("loader1"); loader1.setPath("D:/lib1/"); //loader2的父載入器為loader1 MyClassLoader loader2 = new MyClassLoader(loader1, "loader2"); loader2.setPath("D:/lib2/"); //loader3的父載入器為根類載入器 MyClassLoader loader3 = new MyClassLoader(null, "loader3"); loader3.setPath("D:/lib3/"); Class clazz = loader2.loadClass("Sample"); Object object = clazz.newInstance(); }}public class Sample { public Sample(){ System.out.println("Sample is loaded by " + this.getClass().getClassLoader()); new A(); }}public class A { public A(){ System.out.println("A is loaded by " + this.getClass().getClassLoader()); }}

每個自己定義ClassLoader都必須繼承ClassLoader這個抽象類別,而每個ClassLoader都會有一個parent ClassLoader。我們能夠看一下ClassLoader這個抽象類別中有一個getParent()方法,這種方法用來返回當前 ClassLoader的parent,注意,這個parent不是指的被繼承的類,而是在執行個體化該ClassLoader時指定的一個 ClassLoader,假設這個parent為null,那麼就預設該ClassLoader的parent是bootstrap classloade。

上面解說了一下ClassLoader的作用以及一個最主要的載入流程,接下來我們說說ClassLoader使用了雙親託付模式進行類載入。

ClassLoader雙親託付模式

通俗的講,就是某個特定的類載入器在接到載入類的請求時,首先將載入任務託付給父類載入器。依次遞迴。假設父類載入器能夠完畢類載入任務,就成功返回;僅僅有父類載入器無法完畢此載入任務時,才自己去載入。

為了更好的理解雙親託付模式,我們先自己定義一個ClassLoader,假設我們使用這個自己定義的ClassLoader載入 java.lang.String,那麼這裡String是否會被這個ClassLoader載入呢?

其實java.lang.String這個類並不會被我們自己定義的classloader載入。而是由bootstrap classloader進行載入,為什麼會這樣?實際上這就是雙親託付模式的原因,由於在不論什麼一個自己定義ClassLoader載入一個類之前,它都會先 託付它的父親ClassLoader進行載入,僅僅有當父親ClassLoader無法載入成功後,才會由自己載入。

而在上面的範例中,由於 java.lang.String是屬於java核心API的一個類,所以當使用自己定義的classloader載入它的時候。該 ClassLoader會先託付它的父親ClassLoader進行載入(bootstrap classloader),所以並不會被我們自己定義的ClassLoader載入。

我們來看一下ClassLoader的一段原始碼:

protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException{           // 首先檢查該name指定的class是否有被載入           Class c = findLoadedClass(name);           if (c == null) {               try {                   if (parent != null) {                       //假設parent不為null,則調用parent的loadClass進行載入                       c = parent.loadClass(name, false);                   }else{                       //parent為null,則調用BootstrapClassLoader進行載入                       c = findBootstrapClass0(name);                   }               }catch(ClassNotFoundException e) {                   //假設仍然無法載入成功,則調用自身的findClass進行載入                               c = findClass(name);               }           }           if (resolve) {               resolveClass(c);           }           return c;      }
使用雙親託付模式長處

那麼我們使用雙親託付模式有什麼長處呢?

  1. 由於這樣能夠避免反覆載入。當父親已經載入了該類的時候,就沒有必要子ClassLoader再載入一次。

  2. 考慮到安全因素,我們試想一下,假設不使用這樣的託付模式,那我們就能夠隨時使用自己定義的String來動態替代java核心api中定義類型,這樣會存在很大的安全隱患。而雙親託付的方式,就能夠避免這樣的情況,由於String已經在啟動時被載入,所以使用者自己定義類是無法載入一個自己定義的ClassLoader。

附:Android ClassLoader簡單介紹

android classloader雙親託付模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.