<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    The NoteBook of EricKong

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks

          JVM在運行時會產生三個ClassLoader,Bootstrap ClassLoaderExtension ClassLoaderAppClassLoader.其中,Bootstrap是用C++編寫的,我們在Java中看不到它,是null。它用來加載核心類庫,在JVM源代碼中這樣寫道:
    static const char classpathFormat[] =
    "%/lib/rt.jar:"
    "%/lib/i18n.jar:"
    "%/lib/sunrsasign.jar:"
    "%/lib/jsse.jar:"
    "%/lib/jce.jar:"
    "%/lib/charsets.jar:"
    "%/classes";
          知道為什么不需要在classpath中加載這些類了吧?人家在JVM啟動的時候就自動加載了,并且在運行過程中根本不能修改Bootstrap加載路徑。Extension ClassLoader用來加載擴展類,即/lib/ext中的類。最后AppClassLoader才是加載Classpath的。
          ClassLoader加載類用的是委托模型。即先讓Parent類(而不是Super,不是繼承關系)尋找,Parent找不到才自己找。看來ClassLoader還是蠻孝順的。三者的關系為:AppClassLoader的Parent是ExtClassLoader,而ExtClassLoader的Parent為Bootstrap ClassLoader。加載一個類時,首先BootStrap先進行尋找,找不到再由ExtClassLoader尋找,最后才是AppClassLoader。
         為什么要設計的這么復雜呢?其中一個重要原因就是安全性。比如在Applet中,如果編寫了一個java.lang.String類并具有破壞性。假如不采用這種委托機制,就會將這個具有破壞性的String加載到了用戶機器上,導致破壞用戶安全。但采用這種委托機制則不會出現這種情況。因為要加載java.lang.String類時,系統最終會由Bootstrap進行加載,這個具有破壞性的String永遠沒有機會加載。
    我們來看這段代碼:

    //A.java
    public class A{
        
    public static void main(String[] args){
            A a
    =new A();
            System.out.println(System.getProperty(
    "java.ext.dirs"));
            System.out.println(a.getClass().getClassLoader());
            B b
    =new B();
            b.print();
        }

    }

    //B.java
    public class B{
        
    public void print(){
            System.out.println(
    this.getClass().getClassLoader());
        }

    }

    1、我們將它放在Classpath中,則打印出
    sun.misc.Launcher$AppClassLoader@92e78c
    sun.misc.Launcher$AppClassLoader@92e78c
    可見都是由AppClassLoader來加載的。
    2
    、我們將其放在%jre%/lib/ext/classes(ExtClassLoader的加載目錄。其加載/lib/ext中的jar文件或者子目錄classes中的class文件)中。則會打印出:
    sun.misc.Launcher$ExtClassLoader
    sun.misc.Launcher$ExtClassLoader
    3
    、我們將A.class放到%jre%/lib/ext/classes中,而將B.class放到classpaht中又會怎么樣呢?結果是:
    sun.misc.Launcher$ExtClassLoader
    Exception in thread "main" java.lang.NoClassDefFoundError:B
        at A.main(A.java:6)
    怎么會這樣呢?這其中有一個重要的問題:A類當然是由ExtClassLoader來加載的,B類要由哪個加載呢?B類要由調用它自己的類的類加載器(真拗口)。也就是說,A調用了B,所以BA的類加載器ExtClassLoader來加載。ExtClassLoader根據委托機制,先拜托Bootstrap加載,Bootstrap沒有找到。然后它再自己尋找B類,還是沒找到,所以拋出異常。ExtClassLoader不會請求AppClassLoader來加載!你可能會想:這算什么問題,我把兩個類放到一起不就行了?
        呵呵,沒這么簡單。比如JDBC是核心類庫,而各個數據庫的JDBC驅動則是擴展類庫或在classpath中定義的。所以JDBCBootstrap ClassLoader加載,而驅動要由AppClassLoader加載。等等,問題來了,Bootstrap不會請求AppClassLoader加載類啊。那么,他們怎么實現的呢?我就涉及到一個Context ClassLoader的問題,調用Thread.getContextClassLoader

    1 - Tomcat的類載入器的結構

    Tomcat Server在啟動的時候將構造一個ClassLoader樹,以保證模塊的類庫是私有的
    Tomcat Server的ClassLoader結構如下:

            +-----------------------------+
            |         Bootstrap           |
            |             |               |
            |          System             |
            |             |               |
            |          Common             |
            |         /      \            |
            |     Catalina Shared        |
            |               /    \        |
            |          WebApp1 WebApp2   |
            +-----------------------------+

    其中:
    - Bootstrap -
    載入JVM自帶的類和$JAVA_HOME/jre/lib/ext/*.jar
    - System     -
    載入$CLASSPATH/*.class
    - Common   -
    載入$CATALINA_HOME/common/...,它們對TOMCAT和所有的WEB APP都可見
    - Catalina    -
    載入$CATALINA_HOME/server/...,  它們僅對TOMCAT可見,對所有的WEB APP都不可見
    - Shared      -
    載入$CATALINA_HOME/shared/..., 它們僅對所有WEB APP可見,對TOMCAT不可見(也不必見)
    - WebApp    - 
    載入ContextBase/WEB-INF/...,    它們僅對該WEB APP可見

     
    2 - ClassLoader的工作原理 
          每個運行中的線程都有一個成員contextClassLoader,用來在運行時動態地載入其它類系統默認的contextClassLoader是systemClassLoader,所以一般而言java程序在執行時可以使用JVM自帶的類、$JAVA_HOME/jre/lib/ext/中的類和$CLASSPATH/中的類可以使用Thread.currentThread().setContextClassLoader(...);更改當前線程的contextClassLoader,來改變其載入類的行為ClassLoader被組織成樹形,一般的工作原理是:
    1) 線程需要用到某個類,于是contextClassLoader被請求來載入該類
    2) contextClassLoader請求它的父ClassLoader來完成該載入請求
    3) 如果父ClassLoader無法載入類,則contextClassLoader試圖自己來載入
        注意:WebApp ClassLoader的工作原理和上述有少許不同:
        它先試圖自己載入類(在ContextBase/WEB-INF/...中載入類),如果無法載入,再請求父ClassLoader完成
    由此可得:
        - 對于WEB APP線程,它的contextClassLoader是WebApp ClassLoader
        - 對于Tomcat Server線程,它的contextClassLoader是CatalinaClassLoader


    3 - 部分原代碼分析
     
    3.1 - org/apache/catalina/startup/Bootstrap.java
    Tomcat Server線程的起點
    構造ClassLoader樹,并設置Tomcat Server線程的contextClassLoader為catalinaloader
    載入若干類,然后轉入org.apache.catalina.startup.Catalina類中
    package org.apache.catalina.startup;

     

    // JDK類庫
    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.ArrayList;

    //apache自己的類庫
    import org.apache.catalina.loader.Extension;
    import org.apache.catalina.loader.StandardClassLoader;



    /**
     * Boostrap loader for Catalina.  This application constructs a class loader
     * for use in loading the Catalina internal classes (by accumulating all of the
     * JAR files found in the "server" directory under "catalina.home"), and
     * starts the regular execution of the container.  The purpose of this
     * roundabout approach is to keep the Catalina internal classes (and any
     * other classes they depend on, such as an XML parser) out of the system
     * class path and therefore not visible to application level classes.
     *
     * 
    @author Craig R. McClanahan
     * 
    @version $Revision: 1.36 $ $Date: 2002/04/01 19:51:31 $
     
    */


    /**
     * 該類的main方法的主要任務:
     * --------------------------
     *
     * 1,創建TOMCAT自己的類載入器(ClassLoader)
     *      +---------------------------+
     *      |         Bootstrap         |
     *      |             |             |
     *      |          System           |
     *      |             |             |
     *      |          Common           |
     *      |         /      \          |
     *      |     Catalina  Shared      |
     *      +---------------------------+
     *    其中:
     *    - Bootstrap - 載入JVM自帶的類和$JAVA_HOME/jre/lib/ext/*.jar
     *    - System    - 載入$CLASSPATH/*.class
     *    - Common    - 載入$CATALINA_HOME/common/,它們對TOMCAT和所有的WEB APP都可見
     *    - Catalina  - 載入$CATALINA_HOME/server/,它們僅對TOMCAT可見,對所有的WEB APP都不可見
     *    - Shared    - 載入$CATALINA_HOME/shared/,它們僅對所有WEB APP可見,對TOMCAT不可見(也不必見)
     *    注意:當一個ClassLoader被請求載入一個類時,它首先請求其父ClassLoader完成載入,
     *    僅當其父ClassLoader無法載入該類時,才試圖自己載入該類
     * 2,改變本身線程的默認ClassLoader(本線程就是Tomcat Server線程,類載入器是catalinaLoader)
     * 3,讓catalinaLoader載入一些類,類的位置在$CATALINA_HOME/server/lib/catalina.jar中
     * 4,創建org.apache.catalina.startup.Catalina類的一個實例startupInstance,并為其調用方法:
     *    startupInstance.setParentClassLoader(sharedLoader);
     *    startupInstance.process(args);
     *
     *
     * 有關ClassLoader的說明:
     * -----------------------
     *
     * 每個被DEPLOY的WEB APP都會被創建一個ClassLoader,用來載入該WEB APP自己的類
     * 這些類的位置是webappX/WEB-INF/classes/*.class和webappX/WEB-INF/lib/*.jar
     *
     * ClassLoader的工作流程是:
     * 1) 收到一個載入類的的請求
     * 2) 請求其父ClassLoader來完成該類的載入
     * 3) 如果父ClassLoader無法載入,則自己試圖完成該類的載入
     *
     * 特別注意WEB APP自己的ClassLoader的實現與眾不同:
     * 它先試圖從WEB APP自己的目錄里載入,如果失敗則請求父ClassLoader的代理
     * 這樣可以讓不同的WEB APP之間的類載入互不干擾
     *
     * WEB APP的ClassLoader的層次結構是:
     *     +----------------------------+
     *     |       Shared               |
     *     |      /      \           |
     *     |   Webapp1  Webapp2      |
     *     +----------------------------+
     * 故對于一個WEB APP,其類載入的優先順序如下:
     * - /WEB-INF/classes/*.class 和 /WEB-INF/lib/*.jar
     * - Bootstrap classes of JVM
     * - System class loader classes
     * - $CATALINA_HOME/common/
     * - $CATALINA_HOME/shared/
     *
     *
     * 小結:
     * ------
     *
     * 綜上分析
     * - Tomcat Server線程使用的classLoader是Catalina
     * - 每個WEB APP線程使用的classloader是Webapp?
     *
     
    */



    public final class Bootstrap {
        
    /**
         * DEBUG級別
         
    */

        
    private static int debug = 0;
        
    /**
         * 腳本執行該程序時,提供以下的系統屬性:
         * java.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
         * java.security.manager \
         * java.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
         * catalina.base="$CATALINA_BASE" \
         * catalina.home="$CATALINA_HOME" \
         * java.io.tmpdir="$CATALINA_TMPDIR" \
         *
         * 
    @param args Command line arguments to be processed
         
    */

        
    public static void main(String args[]) {
            
    // 設置debug
            for (int i = 0; i < args.length; i++)  {
                
    if ("-debug".equals(args[i]))
                    debug 
    = 1;
            }

            
    // 設置好系統屬性catalina.base,即保證其有值
            if (System.getProperty("catalina.base"== null)
                System.setProperty(
    "catalina.base", getCatalinaHome());
            
    // 創建三個ClassLoader
            
    // 這三個對象是通過ClassLoaderFactory的靜態方法創建的
            
    // 其實際類型是StandardClassLoader,完成tomcat自定義的類載入
            
    // 這些類對非tomcat及其上的webapp的其它java程序不可見,故用自己的Classloader載入
            ClassLoader commonLoader = null;
            ClassLoader catalinaLoader 
    = null;
            ClassLoader sharedLoader 
    = null;
            
    try {
                File unpacked[] 
    = new File[1];
                File packed[] 
    = new File[1];
                File packed2[] 
    = new File[2];    
                ClassLoaderFactory.setDebug(debug);


                
    // $CATALINA_HOME/common/classes/*.class - 未壓縮的類
                
    // $CATALINA_HOME/common/endorsed/*.jar - 壓縮的類(endorse:支持)
                
    // $CATALINA_HOME/common/lib/*.jar - 壓縮的類
                
    // 這些類是被tomcat server以及所有的webapp所共享的類,由commonLoader負責載入

                unpacked[
    0= new File(getCatalinaHome(),"common" + File.separator + "classes");
                packed2[
    0=  new File(getCatalinaHome(),"common" + File.separator + "endorsed");
                packed2[
    1=  new File(getCatalinaHome(),"common" + File.separator + "lib");
                commonLoader 
    = ClassLoaderFactory.createClassLoader(unpacked, packed2, null);

                
    // $CATALINA_HOME/server/classes/*.class
                
    // $CATALINA_HOME/server/lib/*.jar
                
    // 這些類是僅被tomcat server使用而對webapp不可見的類,由catalinaLoader負責載入

                unpacked[
    0= new File(getCatalinaHome(),"server" + File.separator + "classes");
                packed[
    0]     = new File(getCatalinaHome(),"server" + File.separator + "lib");
                catalinaLoader 
    = ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);
     
                
    // $CATALINA_BASE/shared/classes/*.class
                
    // $CATALINA_BASE/shared/lib/*.jar
                
    // 這些類是僅被tomcat的webapp使用的類,由sharedLoader負責載入

                unpacked[
    0]  = new File(getCatalinaBase(),"shared" + File.separator + "classes");
                packed[
    0]      = new File(getCatalinaBase(),"shared" + File.separator + "lib");
                sharedLoader 
    = ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);
                                                         
                
    // 注意三個自己定置的ClassLoader的層次關系:
                
    // systemClassLoader (root)
                
    //   +--- commonLoader
                
    //          +--- catalinaLoader
                
    //          +--- sharedLoader

                        }
     catch (Throwable t) {
                log(
    "Class loader creation threw exception", t);
                System.exit(
    1);

            }


            
    // 為當前的線程更改其contextClassLoader
            
    // 一般的線程默認的contextClassLoader是系統的ClassLoader(所有其它自定義ClassLoader的父親)
            
    // 當該線程需要載入類時,將使用自己的contextClassLoader來尋找并載入類
            
    // 更改contextClassLoader可以更改該線程的尋找和載入類的行為,但不影響到其它線程
            
    // 注意!Tomcat Server線程使用的是catalinaLoader

            Thread.currentThread().setContextClassLoader(catalinaLoader);

            
    // Load our startup class and call its process() method

            
    try {
                
    // 預載入catalinalLoader的一些類
                SecurityClassLoad.securityClassLoad(catalinaLoader);
                
    // 獲得tomcat的啟動類:org.apache.catalina.startup.Catalina,并創建該類的一個實例
                if (debug >= 1)
                    log(
    "Loading startup class");
                Class startupClass 
    = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
                Object startupInstance 
    = startupClass.newInstance();


                
    // 設置startupInstance的父ClassLoader,相當于執行:
                
    // Catalina startupInstance = new Catailina();
                
    // startupInstance.setParentClassLoader(sharedLoader);
                
    // 詳情參考類org.apache.catalina.startup.Catalina

                
    if (debug >= 1)log("Setting startup class properties");
                String methodName 
    = "setParentClassLoader";
                Class paramTypes[] 
    = new Class[1];
                paramTypes[
    0= Class.forName("java.lang.ClassLoader");
                Object paramValues[] 
    = new Object[1];
                paramValues[
    0= sharedLoader;
                Method method 
    =startupInstance.getClass().getMethod(methodName, paramTypes);
                method.invoke(startupInstance, paramValues);


                
    // 使用main方法獲得的參數args來執行process方法,相當于:
                
    // startupInstance.process(args);
                
    // 詳情參考類org.apache.catalina.startup.Catalina

                
    if (debug >= 1)log("Calling startup class process() method");
                methodName 
    = "process";
                paramTypes 
    = new Class[1];
                paramTypes[
    0= args.getClass();
                paramValues 
    = new Object[1];
                paramValues[
    0= args;
                method 
    =startupInstance.getClass().getMethod(methodName, paramTypes);
                method.invoke(startupInstance, paramValues);

                }
     catch (Exception e) {
                System.out.println(
    "Exception during startup processing");
                e.printStackTrace(System.out);
                System.exit(
    2);
                     }


        }


        
    /**
         * 返回$CATALINA_HOME變量。如果該變量沒有定義,則將之賦值為用戶的當前工作目錄。
         
    */

        
    private static String getCatalinaHome() {
            
    return System.getProperty("catalina.home",System.getProperty("user.dir"));
        }

     
        
    /**
         * 返回$CATALINA_BASE變量。如果該變量沒有定義,則將之賦值為$CATALINA_HOME。
         
    */

        
    private static String getCatalinaBase() {
            
    return System.getProperty("catalina.base", getCatalinaHome());
        }


        
    /**
         * 輸出LOG信息。
         
    */

        
    private static void log(String message) {
            System.out.print(
    "Bootstrap: ");
            System.out.println(message);
        }


        
    /**
         * 輸出由異常引起的LOG信息。
         
    */

        
    private static void log(String message, Throwable exception) {
            log(message);
            exception.printStackTrace(System.out);

        }

    }

    3.2 - org/apache/catalina/startup/ClassLoaderFactory.java
    根據設置創建并返回StandardClassLoader的實例

     


    package org.apache.catalina.startup;

    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.jar.JarEntry;
    import java.util.jar.JarFile;

    import org.apache.catalina.loader.StandardClassLoader;


    /**
    * Utility class for building class loaders for Catalina.The factory
    * method requires the following parameters in order to build a new class
    * loader (with suitable defaults in all cases):
    *    A set of directories containing unpacked classes (and resources)
    *         that should be included in the class loader's
    *         repositories.
    *     
    *    A set of directories containing classes and resources in JAR files.
    *         Each readable JAR file discovered in these directories will be
    *         added to the class loader's repositories.
    *     
    *    ClassLoader instance that should become the parent of the new class loader.
    *     
    *
    @author Craig R. McClanahan
    @version $Revision: 1.8 $ $Date: 2002/02/17 08:26:02 $
    */



    public final class ClassLoaderFactory {
       
    /**
         * Debugging detail level for processing the startup.
        
    */

        
    private static int debug = 0;
        
    /**
         * Return the debugging detail level.
         
    */


        
    public static int getDebug() {
            
    return (debug);
        }

        
    /**
         * 設置DEBUG級別
         
    */

        
    public static void setDebug(int newDebug) {
            debug 
    = newDebug;
        }


        
    /**
         * 該類是一個靜態類,用來創建和返回ClassLoader對象(實際上是StandardClassLoader對象)
         * 它將根據設置和參數返回apache定置的ClassLoader對象,以完成自己的類載入
         *
         * 
    @param unpacked 類路徑CLASSPATH的數組
         * 
    @param packed 含有JAR文件的類路徑
         * 
    @param parent 父ClassLoader對象。當一個ClassLoader對象無法完成類載入時,它將請求父對象幫助
         *
         * 
    @exception Exception if an error occurs constructing the class loader
         
    */


        
    public static ClassLoader createClassLoader(File unpacked[],File packed[], ClassLoader parent)
            
    throws Exception {
            
    if (debug >= 1)log("Creating new class loader");
            
    // list里將被填入所有需要附加到CLASSPATH上去的文件名
            ArrayList list = new ArrayList();
            
    // Add unpacked directories
            if (unpacked != null{
                
    for (int i = 0; i < unpacked.length; i++)  {
                    File file 
    = unpacked[i];
                    
    if (!file.isDirectory() || !file.exists() || !file.canRead())continue;
                    
    if (debug >= 1)log("  Including directory " + file.getAbsolutePath());
                    URL url 
    = new URL("file"null,file.getCanonicalPath() + File.separator);
                    list.add(url.toString());
                }

            }

            
    // Add packed directory JAR files
            if (packed != null{
                
    for (int i = 0; i < packed.length; i++{
                    File directory 
    = packed[i];
                    
    if (!directory.isDirectory() || !directory.exists() ||!directory.canRead()) continue;
                    String filenames[] 
    = directory.list();
                    
    for (int j = 0; j < filenames.length; j++{
                        String filename 
    = filenames[j].toLowerCase();
                        
    if (!filename.endsWith(".jar"))continue;
                        File file 
    = new File(directory, filenames[j]);
                        
    if (debug >= 1)log("  Including jar file " + file.getAbsolutePath());
                        URL url 
    = new URL("file"null,file.getCanonicalPath());
                        list.add(url.toString());
                    }

                }

            }

            
    // 填好了list
            
    // 創建StandardClassLoader對象,并返回

            String array[] 
    = (String[]) list.toArray(new String[list.size()]);
            StandardClassLoader classLoader 
    = null;
            
    if (parent == null){
               classLoader 
    = new StandardClassLoader(array); 
            }
    else{
                 classLoader 
    = new StandardClassLoader(array, parent);
            }
               
            classLoader.setDelegate(
    true);
            
    return (classLoader);

        }

        
    /**
         * 輸出日志
         
    */

        
    private static void log(String message) {
            System.out.print(
    "ClassLoaderFactory:  ");
            System.out.println(message);
        }

        
    /**
         * 輸出日志和異常信息
         
    */

        
    private static void log(String message, Throwable exception) {
            log(message);
            exception.printStackTrace(System.out);
        }


    }

    3.3 - org/apache/catalina/loader/StandardClassLoader.java
    類載入器

    3.4 - org/apache/catalina/startup/SecurityClassLoad.java
    該類僅包含一個靜態方法,用來為catalinaLoader載入一些類

     


    package org.apache.catalina.startup;


    /**
     * Static class used to preload java classes when using the
     * Java SecurityManager so that the defineClassInPackage
     * RuntimePermission does not trigger an AccessControlException.
     *
     * 
    @author Glenn L. Nielsen
     * 
    @version $Revision: 1.1 $ $Date: 2001/12/30 01:58:20 $
     
    */




    /**
     * 該類只有一個靜態方法,其作用僅僅相當于一個函數
     * 該靜態方法負責載入一些指定的類
     * package org.apache.catalina.core
     * package org.apache.catalina.connector
     * package org.apache.catalina.loader
     * package org.apache.catalina.session
     * package org.apache.catalina.util
     * 這些包都在$CATALINA_HOME/server/catalina.jar文件中
     * (由此看來,該靜態方法的合法參數僅為catalinaLoader?)
     
    */



    public final class SecurityClassLoad {

        
    static void securityClassLoad(ClassLoader loader)
            
    throws Exception {

            
    if( System.getSecurityManager() == null )return;

            String basePackage 
    = "org.apache.catalina.";
            loader.loadClass(basePackage 
    + "core.ApplicationContext$PrivilegedGetRequestDispatcher");
            loader.loadClass(basePackage 
    + "core.ApplicationContext$PrivilegedGetResource");
            loader.loadClass(basePackage 
    + "core.ApplicationContext$PrivilegedGetResourcePaths");
            loader.loadClass(basePackage 
    + "core.ApplicationContext$PrivilegedLogMessage");
            loader.loadClass(basePackage 
    + "core.ApplicationContext$PrivilegedLogException");
            loader.loadClass(basePackage 
    + "core.ApplicationContext$PrivilegedLogThrowable");
            loader.loadClass(basePackage 
    + "core.ApplicationDispatcher$PrivilegedForward");
            loader.loadClass(basePackage 
    + "core.ApplicationDispatcher$PrivilegedInclude");
            loader.loadClass(basePackage 
    + "core.ContainerBase$PrivilegedAddChild");
            loader.loadClass(basePackage 
    + "connector.HttpRequestBase$PrivilegedGetSession");
            loader.loadClass(basePackage 
    + "connector.HttpResponseBase$PrivilegedFlushBuffer");
            loader.loadClass(basePackage 
    + "loader.WebappClassLoader$PrivilegedFindResource");
            loader.loadClass(basePackage 
    + "session.StandardSession");
            loader.loadClass(basePackage 
    + "util.CookieTools");
            loader.loadClass(basePackage 
    + "util.URL");
            loader.loadClass(basePackage 
    + "util.Enumerator");
            loader.loadClass(
    "javax.servlet.http.Cookie");

        }

    }


    posted on 2011-12-27 10:25 Eric_jiang 閱讀(623) 評論(1)  編輯  收藏 所屬分類: Java

    Feedback

    # re: ClassLoader介紹 2011-12-27 10:29 Eric_jiang
    http://www.jobeast.com/puyufanyi  回復  更多評論
      

    主站蜘蛛池模板: 亚洲电影国产一区| 久久久无码精品亚洲日韩软件| 浮力影院第一页小视频国产在线观看免费 | 亚洲精品色午夜无码专区日韩| 亚洲精品无码久久久久去q| 亚洲成A∨人片在线观看不卡| 亚洲精品免费视频| 亚洲偷自精品三十六区| 亚洲精品V天堂中文字幕| 视频一区二区三区免费观看| 久久精品免费网站网| 亚洲免费在线播放| 日本精品人妻无码免费大全| 免费看国产一级片| 亚洲精品自产拍在线观看| 亚洲成人免费在线观看| 无码天堂va亚洲va在线va| 中国精品一级毛片免费播放| 四虎最新永久免费视频| 国产成人一区二区三区免费视频| 中文字幕亚洲激情| 亚洲福利一区二区精品秒拍| 亚洲AV香蕉一区区二区三区| 丁香花在线观看免费观看图片| 最近免费最新高清中文字幕韩国| 午夜男人一级毛片免费| 亚洲日产无码中文字幕| 精品日韩99亚洲的在线发布| 一级看片免费视频| ww在线观视频免费观看| 伊人久久亚洲综合影院| 久久久久亚洲AV成人片| 理论亚洲区美一区二区三区| 无码一区二区三区免费| 免费真实播放国产乱子伦| 亚洲AV无码一区二区三区系列| 亚洲另类无码一区二区三区| 国产免费无码AV片在线观看不卡 | 国产精品免费观看久久| 亚洲人JIZZ日本人| 亚洲熟妇AV乱码在线观看|