Java自定義類加載器

自定義類加載器的應用場景

  • 加密:如果你不想自己的代碼被反編譯的話。(類加密后就不能再用ClassLoader進行加載了,這時需要自定義一個類加載器先對類進行解密,再加載)。

  • 從非標準的來源加載代碼:如果你的字節(jié)碼存放在數(shù)據(jù)庫甚至是云端,就需要自定義類加載器,從指定來源加載類。

雙親委派

  • 我們先看一下ClassLoader類默認的loadClass方法實現(xiàn)
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 = 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
                //子加載器進行類加載 
                c = findClass(name);
            }
        }
        if (resolve) {
            //判斷是否需要鏈接過程,參數(shù)傳入
            resolveClass(c);
        }
        return c;
    }

雙親委派模型工作過程如下:

(1) 類加載器從已加載的類中查詢該類是否已加載,如果已加載則直接返回。

(2)如果在已加載的類中未找到該類,則委托給父類加載器去加載c = parent.loadClass(name, false),父類也會采用同樣的策略查看自己加載的類中是否包含該類,如果沒有則委托給父類,以此類推一直到啟動類加載起。

(3)如果啟動類加載器加載失?。ɡ缭?code>$JAVA_HOME/jre/lib里未查找到該class),會使用拓展類加載器來嘗試加載,繼續(xù)失敗則會使用AppClassLoader來加載,繼續(xù)失敗則會拋出一個異常ClassNotFoundException,然后再調用當前加載器的findClass()方法進行加載。

雙親委派的好處:

(1)避免自己編寫的類動態(tài)替換java的核心類,比如String

(2)避免了類的重復加載,因為JVM區(qū)分不同類的方式不僅僅根據(jù)類名,相同的class文件被不同的類加載器加載產(chǎn)生的是兩個不同的類。

正題:自定義類加載器

從上面的源碼可以看出調用classLoader時會先根據(jù)委派模型在父類加在其中加載,如果加載失敗則會加載當前加載器的findClass方法來加載,
因此我們自定義的類加載器只需要繼承ClassLoader,并覆蓋findClass方法。

  • 準備一個class文件,編譯后放到D盤根目錄下
public class People {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
  • 自定義類加載器MyClassLoader ,繼承ClassLoader覆蓋findClass方法(其中defineClass方法可以把二進制流字節(jié)組成的文件轉換為一個java.lang.Class
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
 
public class MyClassLoader extends ClassLoader
{
    public MyClassLoader(){}
    
    public MyClassLoader(ClassLoader parent)
    {
        super(parent);
    }
    
    protected Class<?> findClass(String name) throws ClassNotFoundException
    {
        File file = new File("D:/People.class");
        try{
            byte[] bytes = getClassBytes(file);
            //defineClass方法可以把二進制流字節(jié)組成的文件轉換為一個java.lang.Class
            Class<?> c = this.defineClass(name, bytes, 0, bytes.length);
            return c;
        } 
        catch (Exception e)
        {
            e.printStackTrace();
        }
        
        return super.findClass(name);
    }
    
    private byte[] getClassBytes(File file) throws Exception
    {
        // 這里要讀入.class的字節(jié),因此要使用字節(jié)流
        FileInputStream fis = new FileInputStream(file);
        FileChannel fc = fis.getChannel();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        WritableByteChannel wbc = Channels.newChannel(baos);
        ByteBuffer by = ByteBuffer.allocate(1024);
        
        while (true){
            int i = fc.read(by);
            if (i == 0 || i == -1)
            break;
            by.flip();
            wbc.write(by);
            by.clear();
        }
        fis.close();
        return baos.toByteArray();
    }
}
  • 在主函數(shù)中測試一下
MyClassLoader mcl = new MyClassLoader(); 
Class<?> clazz = Class.forName("People", true, mcl); 
Object obj = clazz.newInstance();

System.out.println(obj);
//打印出我們的自定義類加載器
System.out.println(obj.getClass().getClassLoader());


參考鏈接:
https://www.cnblogs.com/gdpuzxs/p/7044963.html
https://blog.csdn.net/seu_calvin/article/details/52315125

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 南風拂面搖得萬木抽芽爭榮 大雁北歸擾動浮云舒卷涌動 乾坤朗朗普度天下水起風生 歲月鐘聲祝您創(chuàng)造快樂心情
    國勝閱讀 345評論 0 0

友情鏈接更多精彩內容