JVM 類加載機制

Java的類加載器都有哪些?

每個類加載器都加載哪些類? 

這些類加載之間的父子關係是怎樣的? 

什麼是雙親委派模型? 

爲什麼Java的類加載器要使用雙親委派模型?  

如何自定義自己的類加載器,自己的類加載器和Java自帶的類加載器關係如何處理?

默認的類加載器只知道如何從本地系統加載類。如果我們的程序只是在本機跑的話,一般來說默認加載器可以應付。 但是如果我們需要加載遠程服務器的類,或者說加載網絡上的,不是本機上的類的時候,就需要到自定義類加載器。

實現方式:
自定義類加載器可以選擇 繼承ClassLoader類,重寫裏面的方法來實現。

1、loadClass(String name,Boolean resolve)方法:不推薦重寫,因爲loadClass()方法做的工作主要爲實現雙親委託模型,我們重寫的話可能會破壞該模型,並且也增加自己的開發難度。
2、defineClass(String name,byte[] b,int off,int len)方法,主要用於將原始字節轉換爲Class對象,也不需要我們重寫。
3、findClass(String name)方法,根據名稱來查找類。把.class文件的內容放入一個byte[]數組中,供defineClass()方法使用。一般我們就重寫這個方法。在這個方法中,我們重新定義從哪裏,怎麼樣讀取文件內容。這樣我們就可以把從本機上改爲從網絡上得到類,從而實現自定義類加載器。

步驟:
1、繼承ClassLoader類。
2、重寫findClass(String name)方法。 在這個方法裏面我們重新定義從哪裏,怎麼讀取文件內容到byte[]數組中,供defineClass()使用

package com.study.pattern;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

/**
 * Created by WuTing on 2018/3/6.
 */
public class MyClassLoader extends ClassLoader {
    private static final String FILE_TYPE = ".class";

    private String path;

    public MyClassLoader() {
        super();
    }

    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    @Override
    public Class<?> loadClass(String classFullName) throws ClassNotFoundException {
        return super.loadClass(classFullName);
    }

    @Override
    protected Class<?> loadClass(String classFullName, boolean resolve) throws ClassNotFoundException {
        return super.loadClass(classFullName, resolve);
    }

    @Override
    protected Class<?> findClass(String classFullName) throws ClassNotFoundException {
        byte[] data = this.loadClassData(classFullName);
        return this.defineClass(classFullName, data, 0, data.length);
    }

    private byte[] loadClassData(String classFullName) {
        InputStream is = null;
        byte[] data = null;
        ByteArrayOutputStream outputStream = null;
        try {
            String pathname = getPath() + classFullName.replace(".", "\\") + FILE_TYPE;
            is = new FileInputStream(new File(pathname));
            outputStream = new ByteArrayOutputStream();
            int ch = 0;
            while (-1 != (ch = is.read())) {
                outputStream.write(ch);
            }
            data = outputStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    public static void showClassLoader(ClassLoader loader) throws Exception {
        Class clazz = loader.loadClass("com.study.pattern.Sample"); //Class 全名
        clazz.newInstance();
    }

    public static void main(String[] args) throws Exception {
        MyClassLoader loader1 = new MyClassLoader();
        loader1.setPath("d:\\loader1\\");

        MyClassLoader loader2 = new MyClassLoader(loader1);
        loader2.setPath("d:\\loader2\\");

        MyClassLoader loader3 = new MyClassLoader(null);
        loader3.setPath("d:\\loader3\\");

        showClassLoader(loader1);
        showClassLoader(loader2);
        showClassLoader(loader3);
    }

    public String getPath() {
        if (path == null || path.trim().length() == 0) {
            path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        }
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}
package com.study.pattern;

/**
 * Created by WuTing on 2018/3/6.
 */
public class Sample {
    public Sample() {
        System.out.println("Sample is load by :" + this.getClass().getClassLoader());
    }
}

執行結果:

Sample is load by :sun.misc.Launcher$AppClassLoader@18b4aac2
Sample is load by :sun.misc.Launcher$AppClassLoader@18b4aac2
Sample is load by :com.study.pattern.MyClassLoader@1540e19d

從結果可以看出,當指定了指定了parent,會調用parent的findClass.

  protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) { //存在parent,調用parent的loadClass
                        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.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章