之前沒想過這麼個問題:Tomcat怎麼處理webapps下項目,而且我訪問瀏覽器ip: port/項目名/請求路徑,以SSM爲例,Tomcat怎麼就能將請求找到項目呢,項目仍是個文件夾類型的?html
Tomcat部署webapps下項目方法位於:HostConfig#deployApps,別問怎麼知道的,看源碼,也能夠支持看下我前面的博客,雖然介紹粗心大意,可是也能走到這步了。web
介紹下deployApps,最開始獲取兩個配置,分別是catalina-home/webapps以及catalina-home/conf/Catalina/localhost路徑,filterAppPaths方法呢主要是過濾webapps下不想部署的項目,好比你有些大項目之前部署的,如今不想用了,可是不想刪除呢?就能夠忽略部署來節省Tomcat啓動時間,具體方式就是在server.xml中Host元素裏添加屬性deployIgnore,支持正則表達式過濾。正則表達式
deployDescriptors、deployWARs是部署特定類型的項目,好比war包等,這裏主要介紹的是deployDirectories,有興趣的能夠自行研究另外兩種.apache
那咱們明白了Tomcat部署項目仍是得靠deployDirectories方法.瀏覽器
HostConfig#deployDirectories方法以下,思路清晰,先介紹個大致,webapps下每一個項目,只要是文件夾的(名字不爲META-INF\WEB-INF)的,都會經過多線程的方式去」部署項目」,(這裏須要說起一點,怕引發誤會,這裏Tomcat默認給配置的ExecutorService初始線程個數、最大線程個數都是1,這個就尷尬了,是啥緣由引發的無從而就,若是調大個數是否能提升銷量有待確認!)下面開始一點點介紹這個「部署」過程.tomcat
name是webapps下各個文件夾類項目的名字,FWD_SLASH_REPLACEMENT就是 # ,VERSION_MARKER就是 ## , 代碼比較簡單,直接看結果,好比webapps下doc目錄,最後獲得的四個屬性值結果就是 baseName就是docs ,version就是 「」,path就是 /docs ,name就是 /docs , 其餘正常項目名不含#都是相似,舉兩個個例:Root目錄,baseName是Root,version就是「」 , path就是 「」, name就是 「」 .多線程
DeployDirectory是HostConfig內部類,實現了Runnable,持有三重要屬性:HostConfig--外部類實例,ContextName--上面初始化的上下文名稱類,File---當前webapps下目錄的File句柄app
run方法是核心,一看還不是調用HostConfig#deployDirectory!webapp
代碼比較長,分紅片斷來記錄: 前幾行打印日誌,就是Tomcat常見到的日誌以下. 而後 xml文件引用指向 webapps下當前正在部署的項目(暫叫A吧),xml指向A項目META-INF/content.xml文件,而xmlCopy指向 catalina-home/conf/Catalina/localhost/A.xml,copyThisXml默認是false,deployThisXML默認是true.ui
Deploying web application directory E:\Tomcat_Source_Code\apache-tomcat-8.0.53-src\catalina-home\webapps\docs
代碼片斷二. 截取了try-catch塊前半段, 因爲deployThisXML默認是true,可是咱們假設content.xml不存在的狀況,就會執行if判斷邏輯最後一段,contextClass默認是StandardContext,因此實例化了一個StandardContext!
代碼片斷三. try-catch塊後半段邏輯:configClass默認是ContextConfig,是個Tomcat的監聽器,實例化後在StandardContext上監聽着,此外StandardContext賦值四個ContextName的屬性.
而後將StandardContext和StandardHost關聯起來! 代碼片斷四.finally塊作了一些收尾工做,這個留待時候再分析,先分析StandardContext與StandardHost的關聯!
StandardHost和StandardContext關聯起來步驟比較複雜!
先判斷是否webapps是否有項目名解析以後name同樣的,拋出異常來不容許這樣作!將StandardContext父類設置爲StandardHost,將StandardContext做爲value,項目名name做爲key存入StandardHost的 children屬性中(這也說明StandardHost的getChildren確定是調用children.values()來獲取); 部署一個項目以後就會調用項目StandardContext#start方法,項目啓動以後觸發對應監聽事件. StandardContext#start簡單分析見這裏,Tomcat8源碼筆記(九)組件StandardContext啓動流程--未完待續
代碼片斷四.finally塊
部署完成以後,最終達成這樣的效果,將部署信息存放在HostConfig的deployed中,好比 /docs--對應部署信息.
大致流程粗糙的寫了一遍,具體細節,類我還須要熟悉在記錄吧。