類加載時Class.forName到底用哪個加載器?

結論:Class.forName加載類時,使用當前類被加載時的加載器,因為,被依賴的類也必須使用相同的加載器加載,才能正確加載被加載的類。

最近使用hutool工具加載類jar包中的類時,遇到類找不到的問題。記錄如下

自定義加載方法

class MyLoader{
 /**
     * 自定義加載方法
     * @param jarPath
     */
    public static void loadJar(String jarPath) {
        File jarFile = new File(jarPath);
        // 從URLClassLoader類中獲取類所在文件夾的方法,jar也可以認為是一個文件夾
        Method method = null;
        try {
            method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        } catch (NoSuchMethodException | SecurityException e1) {
            e1.printStackTrace();
        }
        //獲取方法的訪問權限以便寫回
        boolean accessible = method.isAccessible();
        try {
            method.setAccessible(true);
            // 獲取系統(tǒng)類加載器
            URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            URL url = jarFile.toURI().toURL();
            method.invoke(classLoader, url);
            System.out.println(classLoader.getURLs());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            method.setAccessible(accessible);
        }
    }
//測試是否有效
public static void useLoadJar() throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        loadJar("E:\\workspace\\java\\javatest\\businessjar01\\target\\businessjar01-1.0-SNAPSHOT.jar");
        Class<?> business = Class.forName("com.gz.Test");
        Constructor<?> constructor = business.getConstructor();
        Object o = constructor.newInstance();
    }
}

本質是將jar包所在路徑加入到ClassLoader(這里是systemclassloader,與MyLoader加載器相同),而Class.forName("com.gz.Test")這行代碼所在的類MyLoader正是被系統(tǒng)類加載器加載的,所以能正確加載Test。

使用hutool的JarClassLoader.load

JarClassLoader.load(new File("E:\\workspace\\java\\javatest\\businessjar01\\target"));
 Class<?> business = Class.forName("com.gz.Test");
//會找不到Test,報錯:java.lang.ClassNotFoundException: com.gz.Test
        //因為:
        // 當前類的加載器為系統(tǒng)類加載器,所有Class.forName加載時,會使用系統(tǒng)類加載器去加載類。
        //JarClassLoader.load(new File("E:\\workspace\\java\\javatest\\businessjar01\\target"))看hutool的源碼是new JarClassLoader()了一個新的類加載器,因此添加的搜索路徑都是到新的類加載器的,
        //而下面的代碼Class.forName("com.gz.Test");使用當前類加載器加載(MyLoader的加載器,即系統(tǒng)類加載器),因此,Class.forName("com.gz.Test")會使用系統(tǒng)類加載器去加載Test類,但是系統(tǒng)類加載器并
        //沒有被添加Test的路徑,因為JarClassLoader.load()方法,new了一個新的類加載器,Test的路徑被添加到新的類加載器了,所以會報錯.
        Class<?> business = Class.forName("com.gz.Test");
        Constructor<?> constructor = business.getConstructor();
        Object o = constructor.newInstance();

使用hutool的JarClassLoader.loadJar,并制定加載器

JarClassLoader.loadJar((URLClassLoader)ClassLoader.getSystemClassLoader(),new File("E:\\workspace\\java\\javatest\\businessjar01\\target"));
        Class<?> business = Class.forName("com.gz.Test");
        Constructor<?> constructor = business.getConstructor();
        Object o = constructor.newInstance();

可以正確加載,因為制定了加載器為系統(tǒng)類加載器,與Class.forName要使用的加載器相同,所以可以找到Test

使用hutool的ClassLoaderUtil.loadClass

public static void testhutools()throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException{
        Class<?> business = ClassLoaderUtil.loadClass(new File("E:\\workspace\\java\\javatest\\businessjar01\\target"), "com.gz.Test");
        //Class.forName("com.gz.Test");
        Constructor<?> constructor = business.getConstructor();
        Object o = constructor.newInstance();
    }

可以正常加載,通過分析lassLoaderUtil.loadClass源碼,可知道,雖然也是新建了一個JarClassLoader,并將jar路徑添加到這個類加載器,但是加載類時,并沒有使用Class.forName方法,而是使用類加載器的loadClass方法。自然可以把Test加載到jvm。

class.forName和loadclass的不同

可參考文章
https://blog.csdn.net/L13763338360/article/details/106014430/
class.forName()前者除了將類的.class文件加載到jvm中之外,還會對類進行解釋,執(zhí)行類中的static塊。而classLoader只干一件事情,就是將.class文件加載到jvm中,不會執(zhí)行static中的內容,只有在newInstance才會去執(zhí)行static塊。
Class.forName得到的class是已經(jīng)初始化完成的,Classloder.loaderClass得到的class是還沒有鏈接的。

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容