how tomcat works 讀書筆記 八 載入器下
來源:程序員人生 發(fā)布時間:2014-11-18 08:29:45 閱讀次數(shù):2619次
載入類
我們看看之前的文章,這1節(jié)就從SimpleWrapper的loadServlet講起。
SimpleWrapper.java以下(省略了try catch及其他部份代碼)
public Servlet loadServlet() throws ServletException {
...
String actualClass = servletClass;
Loader loader = getLoader();
// Acquire an instance of the class loader to be used
if (loader==null) {
throw new ServletException("No loader.");
}
ClassLoader classLoader = loader.getClassLoader();
if (classLoader!=null) {
classClass = classLoader.loadClass(actualClass);
// Instantiate and initialize an instance of the servlet class itself
servlet = (Servlet) classClass.newInstance();
// Call the initialization method of this servlet
servlet.init(null);
return servlet;
}
我們知道loader.getClassLoader();返回的就是webappclassloader類
看了,關(guān)鍵的地方就是classLoader.loadClass(actualClass);
classLoader.loadClass(actualClass)終究調(diào)用的是以下的方法,resolve為false;
下面的方法很長 但總而言之 也就以下幾步
? 所有加載過的類都要進(jìn)行緩存,所以首先需要檢查本地緩存。
? 如果沒法再本地緩存找到類,使用 java.langClassLoader 類的 findLoaderClass 方法在緩存查找類、
? 如果在兩個緩存中都沒法找到該類,使用系統(tǒng)的類加載器避免從 J2EE 類中覆蓋來的 web 利用程序。
? 如果使用了安全管理器,檢查該類是不是允許加載,如果該類不允許加載,則拋出 ClassNotFoundException 異常。
? 如果要加載的類使用了委派標(biāo)志或該類屬于 trigger 包中,使用父加載器來加載類,如果父加載器為 null,使用系統(tǒng)加載器加載。
? 從當(dāng)前的源中加載類
? 如果在當(dāng)前的源中找不到該類并且沒有使用委派標(biāo)志,使用父類加載器。如果父類加載器為 null,使用系統(tǒng)加載器
? 如果該類依然找不到,拋出 ClassNotFoundException 異常
public Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
if (debug >= 2)
log("loadClass(" + name + ", " + resolve + ")");
Class<?> clazz = null;
// Don't load classes if class loader is stopped
if (!started) { //若webappclassloader沒有啟動....
log("Lifecycle error : CL stopped");
throw new ClassNotFoundException(name);
}
// (0) Check our previously loaded local class cache
clazz = findLoadedClass0(name); //看下面臨時放進(jìn)來的代碼 等因而先在本地存儲的已加載的類(hashmap)中找
if (clazz != null) {
if (debug >= 3)
log(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
/*
protected Class<?> findLoadedClass0(String name) {
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
if (entry != null) {
return entry.loadedClass;
}
return (null);
}
*/
// (0.1) Check our previously loaded class cache
clazz = findLoadedClass(name); //再去虛擬機中去找
if (clazz != null) {
if (debug >= 3)
log(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (0.2) Try loading the class with the system class loader, to prevent
// the webapp from overriding J2SE classes
try {
//system 為系統(tǒng)類加載器 sun.misc.Launcher$AppClassLoader
//先用系統(tǒng)加載器加載
//為何先用系統(tǒng)加載器 如果你寫了1個類 全名為"java.lang.Object" 懂了吧?
//大家可能會想 系統(tǒng)加載器不是甚么都能加載嗎? 那還要后面的代碼做甚么?
//系統(tǒng)加載器的加載目錄是甚么 大家看看就明白了
clazz = system.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
// Ignore
}
//關(guān)于安全的問題 我沒有研究過里面具體的代碼
// (0.5) Permission to http://www.vxbq.cn/access/ this class when using a SecurityManager
if (securityManager != null) {
int i = name.lastIndexOf('.');
if (i >= 0) {
try {
securityManager.checkPackageAccess(name.substring(0,i));
} catch (SecurityException se) {
String error = "Security Violation, attempt to use " +
"Restricted Class: " + name;
System.out.println(error);
se.printStackTrace();
log(error);
throw new ClassNotFoundException(error);
}
}
}
//delegate默許為false
//filter 如果要加載的類是packageTrigers里面所限定的 就返回true
//書上說packageTrigers 里面的包是不允許載入的
//可代碼里沒有體現(xiàn)不能加載呀? 誰知道為何,麻煩告知我1聲
boolean delegateLoad = delegate || filter(name);
System.out.println(delegate+" "+filter(name)+" ddd");
// (1) Delegate to our parent if requested
if (delegateLoad) {
if (debug >= 3)
log(" Delegating to parent classloader");
ClassLoader loader = parent;
System.out.println(loader+" loader");
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (debug >= 3)
log(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
// (2) Search local repositories
//至于repositories屬性 是在webappLoader類start方法里 setRepositories()設(shè)定的
//使用的各個方法以下
//findClass findClassInternal findResourceInternal
//在findResourceInternal中先加載WEB-INF/classes中的文件,然后加載WEB-INF/lib下的jar文件
//最后 resourceEntries.put(name, entry);
//會把加載的enety放入resourceEntries中緩存起來
if (debug >= 3)
log(" Searching local repositories");
try {
clazz = findClass(name);
if (clazz != null) {
if (debug >= 3)
log(" Loading class from local repository");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
//系統(tǒng)加載器前面已加載過來 如果程序能運行到這里就說明系統(tǒng)加載器不行 為何還要再加載1遍
// (3) Delegate to parent unconditionally
if (!delegateLoad) {
if (debug >= 3)
log(" Delegating to parent classloader");
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (debug >= 3)
log(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
// This class was not found
throw new ClassNotFoundException(name);
}
利用程序
在上1節(jié)我們已說過,為了實現(xiàn)在文件變動后容器自動重載,需要在server.xml中配置
<Context path="/myApp" docBase="myApp"/>
現(xiàn)在我們還沒有這個配置文件,替換的,在啟動程序中添加以下代碼:
Context context = new StandardContext();
// StandardContext's start method adds a default mapper
context.setPath("/myApp");
context.setDocBase("myApp");
如果上面的代碼在eclipse中運行,項目根目錄下回產(chǎn)生1個myApp文件夾和work文件夾
在myApp文件夾中在設(shè)置WEB-INF/classes文件夾 里面放置前幾篇博客中使用的兩個servlet的class文件
另外要說明1點,自動重載的方法其實就是對照最后修改時間,詳細(xì)代碼大家看源碼便可。
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進(jìn)行捐贈