JVM在運(yùn)行時(shí)會(huì)產(chǎn)生三個(gè)ClassLoader,Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader.其中,Bootstrap是用C++編寫的,我們?cè)贘ava中看不到它,是null。它用來加載核心類庫(kù),在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啟動(dòng)的時(shí)候就自動(dòng)加載了,并且在運(yùn)行過程中根本不能修改Bootstrap加載路徑。Extension ClassLoader用來加載擴(kuò)展類,即/lib/ext中的類。最后AppClassLoader才是加載Classpath的。
ClassLoader加載類用的是委托模型。即先讓Parent類(而不是Super,不是繼承關(guān)系)尋找,Parent找不到才自己找??磥鞢lassLoader還是蠻孝順的。三者的關(guān)系為:AppClassLoader的Parent是ExtClassLoader,而ExtClassLoader的Parent為Bootstrap ClassLoader。加載一個(gè)類時(shí),首先BootStrap先進(jìn)行尋找,找不到再由ExtClassLoader尋找,最后才是AppClassLoader。
為什么要設(shè)計(jì)的這么復(fù)雜呢?其中一個(gè)重要原因就是安全性。比如在Applet中,如果編寫了一個(gè)java.lang.String類并具有破壞性。假如不采用這種委托機(jī)制,就會(huì)將這個(gè)具有破壞性的String加載到了用戶機(jī)器上,導(dǎo)致破壞用戶安全。但采用這種委托機(jī)制則不會(huì)出現(xiàn)這種情況。因?yàn)橐虞djava.lang.String類時(shí),系統(tǒng)最終會(huì)由Bootstrap進(jìn)行加載,這個(gè)具有破壞性的String永遠(yuǎn)沒有機(jī)會(huì)加載。
我們來看這段代碼:
//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文件)中。則會(huì)打印出:
sun.misc.Launcher$ExtClassLoader
sun.misc.Launcher$ExtClassLoader
3、我們將A.class放到%jre%/lib/ext/classes中,而將B.class放到classpaht中又會(huì)怎么樣呢?結(jié)果是:
sun.misc.Launcher$ExtClassLoader
Exception in thread "main" java.lang.NoClassDefFoundError:B
at A.main(A.java:6)
怎么會(huì)這樣呢?這其中有一個(gè)重要的問題:A類當(dāng)然是由ExtClassLoader來加載的,B類要由哪個(gè)加載呢?B類要由調(diào)用它自己的類的類加載器(真拗口)。也就是說,A調(diào)用了B,所以B由A的類加載器ExtClassLoader來加載。ExtClassLoader根據(jù)委托機(jī)制,先拜托Bootstrap加載,Bootstrap沒有找到。然后它再自己尋找B類,還是沒找到,所以拋出異常。ExtClassLoader不會(huì)請(qǐng)求AppClassLoader來加載!你可能會(huì)想:這算什么問題,我把兩個(gè)類放到一起不就行了?
呵呵,沒這么簡(jiǎn)單。比如JDBC是核心類庫(kù),而各個(gè)數(shù)據(jù)庫(kù)的JDBC驅(qū)動(dòng)則是擴(kuò)展類庫(kù)或在classpath中定義的。所以JDBC由Bootstrap ClassLoader加載,而驅(qū)動(dòng)要由AppClassLoader加載。等等,問題來了,Bootstrap不會(huì)請(qǐng)求AppClassLoader加載類啊。那么,他們?cè)趺磳?shí)現(xiàn)的呢?我就涉及到一個(gè)Context ClassLoader的問題,調(diào)用Thread.getContextClassLoader
1 - Tomcat的類載入器的結(jié)構(gòu)
Tomcat Server在啟動(dòng)的時(shí)候?qū)?gòu)造一個(gè)ClassLoader樹,以保證模塊的類庫(kù)是私有的
Tomcat Server的ClassLoader結(jié)構(gòu)如下:
+-----------------------------+
| Bootstrap |
| | |
| System |
| | |
| Common |
| / \ |
| Catalina Shared |
| / \ |
| WebApp1 WebApp2 |
+-----------------------------+
其中:
- Bootstrap - 載入JVM自帶的類和$JAVA_HOME/jre/lib/ext/*.jar
- System - 載入$CLASSPATH/*.class
- Common - 載入$CATALINA_HOME/common/...,它們對(duì)TOMCAT和所有的WEB APP都可見
- Catalina - 載入$CATALINA_HOME/server/..., 它們僅對(duì)TOMCAT可見,對(duì)所有的WEB APP都不可見
- Shared - 載入$CATALINA_HOME/shared/..., 它們僅對(duì)所有WEB APP可見,對(duì)TOMCAT不可見(也不必見)
- WebApp - 載入ContextBase/WEB-INF/..., 它們僅對(duì)該WEB APP可見
2 - ClassLoader的工作原理
每個(gè)運(yùn)行中的線程都有一個(gè)成員contextClassLoader,用來在運(yùn)行時(shí)動(dòng)態(tài)地載入其它類系統(tǒng)默認(rèn)的contextClassLoader是systemClassLoader,所以一般而言java程序在執(zhí)行時(shí)可以使用JVM自帶的類、$JAVA_HOME/jre/lib/ext/中的類和$CLASSPATH/中的類可以使用Thread.currentThread().setContextClassLoader(...);更改當(dāng)前線程的contextClassLoader,來改變其載入類的行為ClassLoader被組織成樹形,一般的工作原理是:
1) 線程需要用到某個(gè)類,于是contextClassLoader被請(qǐng)求來載入該類
2) contextClassLoader請(qǐng)求它的父ClassLoader來完成該載入請(qǐng)求
3) 如果父ClassLoader無(wú)法載入類,則contextClassLoader試圖自己來載入
注意:WebApp ClassLoader的工作原理和上述有少許不同:
它先試圖自己載入類(在ContextBase/WEB-INF/...中載入類),如果無(wú)法載入,再請(qǐng)求父ClassLoader完成
由此可得:
- 對(duì)于WEB APP線程,它的contextClassLoader是WebApp ClassLoader
- 對(duì)于Tomcat Server線程,它的contextClassLoader是CatalinaClassLoader
3 - 部分原代碼分析
3.1 - org/apache/catalina/startup/Bootstrap.java
Tomcat Server線程的起點(diǎn)
構(gòu)造ClassLoader樹,并設(shè)置Tomcat Server線程的contextClassLoader為catalinaloader
載入若干類,然后轉(zhuǎn)入org.apache.catalina.startup.Catalina類中
package org.apache.catalina.startup;
// JDK類庫(kù)
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自己的類庫(kù)
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方法的主要任務(wù):
* --------------------------
*
* 1,創(chuàng)建TOMCAT自己的類載入器(ClassLoader)
* +---------------------------+
* | Bootstrap |
* | | |
* | System |
* | | |
* | Common |
* | / \ |
* | Catalina Shared |
* +---------------------------+
* 其中:
* - Bootstrap - 載入JVM自帶的類和$JAVA_HOME/jre/lib/ext/*.jar
* - System - 載入$CLASSPATH/*.class
* - Common - 載入$CATALINA_HOME/common/
,它們對(duì)TOMCAT和所有的WEB APP都可見
* - Catalina - 載入$CATALINA_HOME/server/
,它們僅對(duì)TOMCAT可見,對(duì)所有的WEB APP都不可見
* - Shared - 載入$CATALINA_HOME/shared/
,它們僅對(duì)所有WEB APP可見,對(duì)TOMCAT不可見(也不必見)
* 注意:當(dāng)一個(gè)ClassLoader被請(qǐng)求載入一個(gè)類時(shí),它首先請(qǐng)求其父ClassLoader完成載入,
* 僅當(dāng)其父ClassLoader無(wú)法載入該類時(shí),才試圖自己載入該類
* 2,改變本身線程的默認(rèn)ClassLoader(本線程就是Tomcat Server線程,類載入器是catalinaLoader)
* 3,讓catalinaLoader載入一些類,類的位置在$CATALINA_HOME/server/lib/catalina.jar中
* 4,創(chuàng)建org.apache.catalina.startup.Catalina類的一個(gè)實(shí)例startupInstance,并為其調(diào)用方法:
* startupInstance.setParentClassLoader(sharedLoader);
* startupInstance.process(args);
*
*
* 有關(guān)ClassLoader的說明:
* -----------------------
*
* 每個(gè)被DEPLOY的WEB APP都會(huì)被創(chuàng)建一個(gè)ClassLoader,用來載入該WEB APP自己的類
* 這些類的位置是webappX/WEB-INF/classes/*.class和webappX/WEB-INF/lib/*.jar
*
* ClassLoader的工作流程是:
* 1) 收到一個(gè)載入類的的請(qǐng)求
* 2) 請(qǐng)求其父ClassLoader來完成該類的載入
* 3) 如果父ClassLoader無(wú)法載入,則自己試圖完成該類的載入
*
* 特別注意WEB APP自己的ClassLoader的實(shí)現(xiàn)與眾不同:
* 它先試圖從WEB APP自己的目錄里載入,如果失敗則請(qǐng)求父ClassLoader的代理
* 這樣可以讓不同的WEB APP之間的類載入互不干擾
*
* WEB APP的ClassLoader的層次結(jié)構(gòu)是:
* +----------------------------+
* | Shared |
* | / \
|
* | Webapp1 Webapp2
|
* +----------------------------+
* 故對(duì)于一個(gè)WEB APP,其類載入的優(yōu)先順序如下:
* - /WEB-INF/classes/*.class 和 /WEB-INF/lib/*.jar
* - Bootstrap classes of JVM
* - System class loader classes
* - $CATALINA_HOME/common/
* - $CATALINA_HOME/shared/
*
*
* 小結(jié):
* ------
*
* 綜上分析
* - Tomcat Server線程使用的classLoader是Catalina
* - 每個(gè)WEB APP線程使用的classloader是Webapp?
*
*/



public final class Bootstrap
{

/** *//**
* DEBUG級(jí)別
*/
private static int debug = 0;

/** *//**
* 腳本執(zhí)行該程序時(shí),提供以下的系統(tǒng)屬性:
* 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[])
{
// 設(shè)置debug

for (int i = 0; i < args.length; i++)
{
if ("-debug".equals(args[i]))
debug = 1;
}
// 設(shè)置好系統(tǒng)屬性catalina.base,即保證其有值
if (System.getProperty("catalina.base") == null)
System.setProperty("catalina.base", getCatalinaHome());
// 創(chuàng)建三個(gè)ClassLoader
// 這三個(gè)對(duì)象是通過ClassLoaderFactory的靜態(tài)方法創(chuàng)建的
// 其實(shí)際類型是StandardClassLoader,完成tomcat自定義的類載入
// 這些類對(duì)非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負(fù)責(zé)載入

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使用而對(duì)webapp不可見的類,由catalinaLoader負(fù)責(zé)載入

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負(fù)責(zé)載入

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


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

}

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

Thread.currentThread().setContextClassLoader(catalinaLoader);

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


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


// 設(shè)置startupInstance的父ClassLoader,相當(dāng)于執(zhí)行:
// 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方法獲得的參數(shù)args來執(zhí)行process方法,相當(dāng)于:
// 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變量。如果該變量沒有定義,則將之賦值為用戶的當(dāng)前工作目錄。
*/

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
根據(jù)設(shè)置創(chuàng)建并返回StandardClassLoader的實(shí)例

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);
}

/** *//**
* 設(shè)置DEBUG級(jí)別
*/

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


/** *//**
* 該類是一個(gè)靜態(tài)類,用來創(chuàng)建和返回ClassLoader對(duì)象(實(shí)際上是StandardClassLoader對(duì)象)
* 它將根據(jù)設(shè)置和參數(shù)返回apache定置的ClassLoader對(duì)象,以完成自己的類載入
*
* @param unpacked 類路徑CLASSPATH的數(shù)組
* @param packed 含有JAR文件的類路徑
* @param parent 父ClassLoader對(duì)象。當(dāng)一個(gè)ClassLoader對(duì)象無(wú)法完成類載入時(shí),它將請(qǐng)求父對(duì)象幫助
*
* @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
// 創(chuàng)建StandardClassLoader對(duì)象,并返回

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
該類僅包含一個(gè)靜態(tài)方法,用來為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 $
*/




/** *//**
* 該類只有一個(gè)靜態(tài)方法,其作用僅僅相當(dāng)于一個(gè)函數(shù)
* 該靜態(tài)方法負(fù)責(zé)載入一些指定的類
* 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文件中
* (由此看來,該靜態(tài)方法的合法參數(shù)僅為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");

}
}
