ClasssLoader自定義類加載器

作用

  • 編譯器先把java文件編譯成class字節碼文件
  • ClassLoad會把字節碼文件轉換成jvm中的Class對象
  • jvm再把class對象轉成實例對象

ClassLoad在java 中有着非常重要的作用,他主要工作是在Class裝載的加載過程,他的主要作用是 從系統外部獲取二進制數據流。它是java的核心組件,所有的class都是通過ClassLoad進行加載的,ClassLoad負責將class文件裏的二進制流輸入到系統中交給jvm進行連接,初始化操作。

分類

  1. 系統自帶的類加載器
  2. 啓動類加載器(BootStrap) c++編寫 加載核心庫 java.* 3.拓展類加載器 (Extension) java編寫 加載拓展庫 javax.* 4.應用程序加載類(AppClassLoader)java編寫 加載程序所在目錄 5.用戶自定義的類加載器 自定義類加載器 java編寫 定製化加載

我們先了解2個方法

第一個方法 findClass

/**
     * Finds the class with the specified <a href="#name">binary name</a>.
     * This method should be overridden by class loader implementations that
     * follow the delegation model for loading classes, and will be invoked by
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
     * parent class loader for the requested class.  The default implementation
     * throws a <tt>ClassNotFoundException</tt>.
     *
     * @param  name
     *         The <a href="#name">binary name</a> of the class
     *
     * @return  The resulting <tt>Class</tt> object
     *
     * @throws  ClassNotFoundException
     *          If the class could not be found
     *
     * @since  1.2
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

我大概翻譯了一下:

將字節數組轉換爲類Class的實例。必須先解析Class才能使用。

大白話就是,將字節流轉換爲類,找不到就報錯!子類應該覆蓋這個方法
第二個方法 defineClass

protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                         ProtectionDomain protectionDomain)
        throws ClassFormatError
    {
        protectionDomain = preDefineClass(name, protectionDomain);
        String source = defineClassSourceLocation(protectionDomain);
        Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
        postDefineClass(c, protectionDomain);
        return c;
    }

根據其官方文檔,再簡化之後我總結了九個字:將字節數組轉換爲類

模擬一個類,假裝這個類是外部文件!我們通過類加載器去加載這個文件!
我們通過類加載器創建該實例!他就會打印構造函數中的一句話!廢話不多說我們直接上圖吧!


/**
 * 模擬這個類被加載,我們先把他搞成.class文件  然後,他被加載時就會打印空構造方法!
 */
public class TestClasssLoader {
    public TestClasssLoader() {
        System.out.println("Hello ClasssLoader!!!");
    }
}

在本地cmd命令行,通過javac TestClasssLoader.java 編譯此文件,會得到一個.class文件,我們將這個class文件隨便放個地方從!
然後開始編寫我們自己的類加載器!

package com.zanzan.vo;

import lombok.AllArgsConstructor;

import java.io.*;

/**
 * 自定義類加載器
 * @author huangfu
 * @AllArgsConstructor 是lombok一個插件,他就是生成MyClassLoader的構造方法的!你也可以手動生成
 */
@AllArgsConstructor
public class MyClassLoader extends ClassLoader {
    /**
     * .class文件所在位置
     */
    private String path;

    /**
     * 查找類加載器
     * @param name 類名(不帶.class)
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes = new byte[0];
        try {
            //這裏就是爲了獲取.class文件的字節流
            bytes = loadClassFile(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
        /**
         * 開始加載類
         * 四個參數!
         * 1.類的名稱
         * 2. .class文件的字節流
         * 3. 從那個位置開始讀取
         * 4. 讀取多長
         */
        return defineClass(name,bytes,0,bytes.length);
    }

    /**
     * 獲取.class文件的字節流信息
     * @param fileName
     * @return
     * @throws IOException
     */
    private byte[] loadClassFile(String fileName) throws IOException {
        String pathFile = path+File.separator+fileName+".class";
        FileInputStream in = new FileInputStream(pathFile);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int readIndex = -1;
        while ((readIndex = in.read())!=-1){
            out.write(readIndex);
        }
        in.close();
        out.close();
        return out.toByteArray();

    }
}

功能測試

終於,我們的代碼寫完了,我們需要測試一下功能!在測試之前回顧一下java的一個基礎!類在被加載的時候,會自動調用空構造函數!所以我們的外部類,一旦被加載就會打印 Hello ClasssLoader!!!來吧,試一下吧!

public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        MyClassLoader myClassLoader = new MyClassLoader("C:\\Users\\huangfu\\Desktop");
        Class<?> testClasssLoader = myClassLoader.findClass("TestClasssLoader");
        testClasssLoader.newInstance();
    }

結果:

Hello ClassLoader!!!

Process finished with exit code 0

搞定收工!趕緊回去試試吧!
歡迎關注作者哦!

發佈了44 篇原創文章 · 獲贊 87 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章