引入:
在Liferay中部署portlet其細節遠比向tomcat部署一個web應用那麼簡單,這文章就來展示下其中的奧秘。
比如,我們在$LIFERAY_HOME/deploy中丟入一個logsearchportlet的war包時:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/15463531P-0.png" title="21.png" />
分析:
在這個動作發生後,它會被容器的PortletAutoDeployerListener所捕捉,從而進入到deploy()方法中:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1546356332-1.png" title="23.png" />
我們可以看到,第43行它其實會去開啟這個壓縮檔(logsearchportlet-1.1.3-SNAPSHOT.war)然後比較子結構是否為portlet的xml檔案結構,因為滿足,所以我們這裡執行到第46行,換句話說,我們的部署器(deployer)使用的是 PortletAutoDeployer的執行個體。
然後會走到第24行,它封裝了用PortletAutoDeployer來部署我們的war包的細節:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1546354T9-2.png" title="24.png" />
它會去委託PortletAutoDeployer的deployFile(file,context)方法:
首先,在712行,它會去讀寫war包中的liferay-plugin-package.xml檔案:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1546352510-3.png" title="25.png" />
吧讀來的內容存放在類PluginPackage的執行個體中,如下:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/154635C28-4.png" title="26.png" />
然後它在第742行來判斷當前war包版本從pluginpackage中讀來)是否被目標Liferay容器支援,不支援就拋出一個異常:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1546352394-5.png" title="27.png" />
這裡,顯然是支援的,所以跳過這段代碼:
然後第751-763行會從pluginPackage中擷取推薦的上下文名稱,我們這裡獲得的是logsearchportlet,並且設定給pluginPackage的context屬性,最後更新PluginPackage。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/154635HS-6.png" title="28.png" />
接下來會構造部署目錄deployDir路徑
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/154635NS-7.png" title="30.png" />
如上所示,在第765行,如果displayName不為null,則在後面加上.war:
然後來根據伺服器類型來對部署目錄(deployDir)的名字進行進一步處理:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/15463530b-8.png" title="32.png" />
這裡可以看出,如果appServer類型是jboss比較特殊點,但是我們不是jboss,而是tomcat,而且我們unpackWar是true(表明我們要開啟這個war包),所以我們的部署目錄是在剛才的deployDir的路徑基礎上去掉最後4個字元,也就是吧.war去掉,所以在第786行之前,現在的deployDir和displayName的值一摸一樣,因為加上了.war又去掉了.war了。
所以,我們在786行吧部署的目標目錄載入這個部署目錄相對路徑之前,就得到了部署目錄的絕對路徑,果然和我們預期是一致的。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1546352E1-9.png" title="33.png" />
接下來,我們就在788行構造一個File對象指向這個部署目錄,然後進行檔案的產生,複製等操作。
最終會調用deployFile來部署war包到剛才產生的指定部署目錄下:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1546355439-10.png" title="34.png" />
我們來看下它的實現;
撇開一些不重要的東西,我們直接跳到deployFile的第883行,首先可以發現它在$CATALINA_HOME/temp目錄下以時間戳記為檔案名稱建立了一個臨時目錄,這個目錄用於部署過程的臨時目錄,然後在887行,吧我們的war檔案展開到這個temp目錄下:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1546352117-11.png" title="35.png" />
其中,當調用887行的時候,伺服器會列印出一條日誌表明這個展開的io操作進行中
Expanding xxx into xxx/temp/<timestamp>
然後在第888行,我們調用deployDirectory方法來完成具體的部署目錄方法,這步驟非常複雜,具體的過程我會在下面一文章中詳細介紹,總體來說作用是具體的往部署目錄中加入指定的檔案,配置等:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/15463555V-12.png" title="36.png" />
最後在893行,吧臨時目錄刪除,然後整個過程就大功告成了。
總結:
我們這裡站在1000英尺的高度對於吧war包丟到$CATALINA_HOME/deploy目錄後發生的過程進行了非常粗略的分析,大體上說,這其中發生了以下細節:
(1)這個事件會被PortletAutoDeployerListener所捕捉,並且進入其deploy()方法中。
(2)然後為這個war包選擇合適的部署器(deployer),它會去開啟一個Zip流去讀取這個war包並且檢查其結構,因為這個war包有portlet.xml檔案,所以它會讓PortletAutoDeployer充當其部署器。
(3)在PortletAutoDeployer調用deployFile()方法來部署這個war包的時候,它首先會讀取lifery-plugin-package.xml檔案,並且查看這個war包的版本是否被當前目標Liferay伺服器所支援,如果不支援,則停止部署,並且拋出一個異常,如果支援,則繼續。
(4)下面,它的主要事情會去建立一個部署目錄deployDir字串,它的起始值是在portlet的displayName後面加上.war. 然後它會去判斷伺服器類型,然後選擇對deployDir的進一步處理,如果是tomcat伺服器,並且undeployWar設定為true時候,它會吧後面的.war去除,最後,它吧當前的相對deployDir轉為絕對路徑的deployDir。
(5)然後它產生一個File對象指向剛才絕對路徑的deployDir,並且調用deployFile()方法來部署我們的war包到鋼廠在第4步中產生的deployDir部署目錄下,這個方法首先會去在$CATALINA_HOME/temp下面以當前的時間戳記為檔案名稱建立一個部署過程的臨時目錄,然後把被部署的war包展開到這個臨時目錄下, 然後調用deployDirectory方法吧這個臨時目錄下的檔案進行加工,並且丟到最終部署目錄deployDir下,最後吧這個臨時目錄刪除。
這裡其實最讓人感興趣的其實是最後一步deployDirectory吧臨時目錄中的內容加工後複製到最終部署目錄的細節,因為太複雜, 所以我想用一篇新的文章分析。
本文出自 “平行線的凝聚” 部落格,請務必保留此出處http://supercharles888.blog.51cto.com/609344/1286593