類裝載器ClassLoader

一、類裝載器的工做機制html

  類裝載器就是類的字節碼文件並構造出類在JVM內部表示對象的組件。在Java中,類裝載器把一個類裝入JVM中,須要如下步驟:java

  (1)裝載:查找和導入Class文件安全

  (2)連接:執行校驗、準備和解析步驟,其中解析步驟是能夠選擇的。jsp

    校驗:檢查載入Class文件數據的正確性。ide

    準備:給類的靜態變量分配存儲空間。工具

    解析:將符號引用轉換成直接引用。this

  (3)初始化:對類的靜態變量、靜態代碼塊執行初始化工做。lua

  類裝載工做由ClassLoader及其子類負責。ClassLoader是一個重要的Java運行時系統組件,它負責在運行時查找和裝入Class字節碼文件。JVM在運行時會產生3個ClassLoader:根裝載器、ExtClassLoader(擴展類裝載器)和AppClassLoader(應用類裝載器)。其中根裝載器不是ClassLoader的子類,它使用C++語言編寫,於是在Java中看不到它,根裝載器負責裝載JRE的核心類庫,如JRE目標下的rt.jar、charsets.jar等。ExtClassLoader和AppClassLoader都是ClassLoader的子類,其中ExtClassLoader負責裝載JRE擴展目錄ext中的JAR類包;AppClassLoader負責裝載Classpath路徑下的類包。spa

  這三個類裝載器之間存在父子層級關係,即根裝載器是ExtClassLoader的父裝載器,ExtClassLoader是AppClassLoader的父裝載器。在默認狀況下,使用AppClassLoader裝載應用程序的類。.net

  實驗代碼:

  

public static void main(String[] args) {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        System.out.println("current loader:" + loader);
        System.out.println("parent loader:" + loader.getParent());
        System.out.println("grandparent loader:" + loader.getParent().getParent());
    }
View Code

  輸出:  

current loader:sun.misc.Launcher$AppClassLoader@18b4aac2
parent loader:sun.misc.Launcher$ExtClassLoader@66d3c617
grandparent loader:null
View Code

  說明:

  根裝載器在Java中訪問不到,因此返回null

  擴展:

  JVM裝載類時使用「全盤負責委託機制

  全盤負責:是指當一個ClassLoader裝載一個類是,除非顯式地使用另外一個ClassLoader,該類所依賴的及引用的類也由這個ClassLoader載入;

  委託機制:是指先委託父裝載器尋找目標類,只有在找不到的狀況下才能從本身的類路徑下查找並裝載目標類。

  這樣的設計是從安全角度考慮的,試想,若是有人編寫了一個惡意的基礎類(如java.lang.String)並裝載到JVM中,將會引發多麼可怕的後果?

實戰經驗:

  在此我提供一個工具類,經過改類能夠方便的查看JVM從哪一個類包中加載指定類:

  訪問方式:http://localhost:8080/srcAdd.jsp?className=java.net.URL

  工具類頁面:

<%@page contentType="text/html; charset=GBK" %>
<%@page import="java.security.*,java.net.*,java.io.*" %>
<%!
    public static URL getClassLocation(final Class cls) {
        if (cls == null) throw new IllegalArgumentException("null input: cls");
        URL result = null;
        final String clsAsResource = cls.getName().replace('.', '/').concat(".class");
        final ProtectionDomain pd = cls.getProtectionDomain();
        // java.lang.Class contract does not specify if 'pd' can ever be null;
        // it is not the case for Sun's implementations, but guard against null
        // just in case:
        if (pd != null) {
            final CodeSource cs = pd.getCodeSource();
            // 'cs' can be null depending on the classloader behavior:
            if (cs != null) result = cs.getLocation();
            if (result != null) {
                // Convert a code source location into a full class file location
                // for some common cases:
                if ("file".equals(result.getProtocol())) {
                    try {
                        if (result.toExternalForm().endsWith(".jar") ||
                                result.toExternalForm().endsWith(".zip"))
                            result = new URL("jar:".concat(result.toExternalForm())
                                                   .concat("!/").concat(clsAsResource));
                        else if (new File(result.getFile()).isDirectory())
                            result = new URL(result, clsAsResource);
                    } catch (MalformedURLException ignore) {
                    }
                }
            }
        }
        if (result == null) {
            // Try to find 'cls' definition as a resource; this is not
            // document.d to be legal, but Sun's implementations seem to         //allow this:
            final ClassLoader clsLoader = cls.getClassLoader();
            result = clsLoader != null ?
                    clsLoader.getResource(clsAsResource) :
                    ClassLoader.getSystemResource(clsAsResource);
        }
        return result;
    }
%>
<html>
<head>
    <title>srcAdd.jar</title>
</head>
<body bgcolor="#ffffff">
使用方法,className參數爲類的全名,不須要.class後綴,如
srcAdd.jsp?className=java.net.URL
<%
    try {
        String classLocation = null;
        String error = null;
        String className = request.getParameter("className");

        classLocation = "" + getClassLocation(Class.forName(className));
        if (error == null) {
            out.print("類" + className + "實例的物理文件位於:");
            out.print("<hr>");
            out.print(classLocation);
        } else {
            out.print("類" + className + "沒有對應的物理文件。<br>");
            out.print("錯誤:" + error);
        }
    } catch (Exception e) {
        out.print("異常。" + e.getMessage());
    }
%>
</body>
</html>
View Code

  工具類:

  在IDEA斷點調試的時候,按Alt+F8,彈出Evluate Expression對話框,在Expression處輸入:ClassLocationUtils.where(<類名>.class) 便可獲知當前類是從哪一個jar包中加載的。

  

/**
 * tools to find which jar does the class come from
 *
 * @author : chenxh,ascend
 */
public class ClassLocationUtils {

    /**
     * find the location of the class come from
     *
     * @param cls Class
     * @return String
     */
    public static String where(final Class cls) {
        if (cls == null) throw new IllegalArgumentException("null input: cls");
        URL result = null;
        final String clsAsResource = cls.getName().replace('.', '/').concat(".class");
        final ProtectionDomain pd = cls.getProtectionDomain();
        if (pd != null) {
            final CodeSource cs = pd.getCodeSource();
            if (cs != null) result = cs.getLocation();
            if (result != null && "file".equals(result.getProtocol())) {
                try {
                    if (result.toExternalForm().endsWith(".jar") ||
                            result.toExternalForm().endsWith(".zip"))
                        result = new URL("jar:".concat(result.toExternalForm())
                                               .concat("!/").concat(clsAsResource));
                    else if (new File(result.getFile()).isDirectory())
                        result = new URL(result, clsAsResource);
                } catch (MalformedURLException ignore) {
                }

            }
        }
        if (result == null) {
            final ClassLoader clsLoader = cls.getClassLoader();
            result = clsLoader != null ?
                    clsLoader.getResource(clsAsResource) :
                    ClassLoader.getSystemResource(clsAsResource);
        }
        return result.toString();
    }

}
View Code

 

碼字不易,尊重原創:http://www.cnblogs.com/adeng/p/7596818.html

相關文章
相關標籤/搜索