淺談Tomcat熱部署原理
tomcat的熱部署實現原理:tomcat啟動的時候會有啟動一個線程每隔一段時間會去判斷應用中加載的類是否發生變法(類總數的變化,類的修改),如果發生了變化就會把應用的啟動的線程停止掉,清除引用,並且把加載該應用的WebappClassLoader設為null,然后創建一個新的WebappClassLoader來重新加載應用。 tomcat中熱部署發現類變法之后要做的一系列停止工作的時序圖如下:

上面時序圖中只把關鍵的流轉步驟畫出來了,還有一些細節的處理沒有完全畫出來,這部分代碼的繼承的結構還是比較復雜的,debug上面的流程的時候,各種跳轉。先解釋一下上面的時序圖,這個時序圖是從WebappLoader的backgroundProcess()方法開始的,backgroundProcess()就是隨tomcat啟動的時候啟動的線程中其中的一方法,是tomcat熱部署代碼的入口。 其中最關鍵的兩步。就是WebappLoader的stopInternal()方法和WebappClassLoader的stop()方法。 在WebappLoader的stopInternal()中
protected void stopInternal() throws LifecycleException { ….. // Throw away our current class loader ((Lifecycle) classLoader).stop(); …….. classLoader = null; }
在 ((Lifecycle) classLoader).stop(); 中classLoader是WebappClassLoader的實例。也就是調用了WebappClassLoader的stop()方法。如下:
public void stop() throws LifecycleException { // Clearing references should be done before setting started to // false, due to possible side effects clearReferences(); started = false; int length = files.length; for (int i = 0; i < length; i++) { files[i] = null; } length = jarFiles.length; for (int i = 0; i < length; i++) { try { if (jarFiles[i] != null) { jarFiles[i].close(); } } catch (IOException e) { // Ignore } jarFiles[i] = null; } notFoundResources.clear(); resourceEntries.clear(); resources = null; repositories = null; repositoryURLs = null; files = null; jarFiles = null; jarRealFiles = null; jarPath = null; jarNames = null; lastModifiedDates = null; paths = null; hasExternalRepositories = false; parent = null; permissionList.clear(); loaderPC.clear(); if (loaderDir != null) { deleteDir(loaderDir); } }
可以看到stop()方法做了很多清除引用的工作。其中 clearReferences() 中
protected void clearReferences() { // De-register any remaining JDBC drivers clearReferencesJdbc(); // Stop any threads the web application started clearReferencesThreads(); // Check for leaks triggered by ThreadLocals loaded by this class loader checkThreadLocalsForLeaks(); // Clear RMI Targets loaded by this class loader clearReferencesRmiTargets(); // Null out any static or final fields from loaded classes, // as a workaround for apparent garbage collection bugs if (clearReferencesStatic) { clearReferencesStaticFinal(); } // Clear the IntrospectionUtils cache. IntrospectionUtils.clear(); // Clear the classloader reference in common-logging if (clearReferencesLogFactoryRelease) { org.apache.juli.logging.LogFactory.release(this); } // Clear the resource bundle cache // This shouldn’t be necessary, the cache uses weak references but // it has caused leaks. Oddly, using the leak detection code in // standard host allows the class loader to be GC’d. This has been seen // on Sun but not IBM JREs. Maybe a bug in Sun’s GC impl? clearReferencesResourceBundles(); // Clear the classloader reference in the VM’s bean introspector java.beans.Introspector.flushCaches(); }
還進行了清除應用線程等工作。最后在WebappClassLoader的stopInternal()方法中執行了 classLoader = null; 那這個類加載器的實例就沒有被引用了。 最后調用WebappLoader中的startInternal()方法,創建新的WebappClassLoader實例,然后開始重新加載應用。到此tomcat的熱部署流程就完成了。