引入:
在上文http://supercharles888.blog.51cto.com/609344/1286631中,我們提到,deployDirectory過程非常複雜,而其中最重要的步驟之一就是更新webXML,它包含若干檔案的更新,包括web.xml,liferay-web.xml ,而且這些xml檔案是最後單獨複製到liferay tomcat webapps的應用部署目錄中的,當時我提到這一步複雜極了,需要另起一篇文章來講解,所以這裡就專門講解這個updateWebXml()方法的細節:
調試過程:
(1)首先,它會去讀我們$CATALINA_HOME/temp/時間戳記目錄下,也就是我們的war分發包展開後的web.xml檔案,這個原始檔案的內容我們會讀到字串content 中。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542112258-0.png" title="1.png" />
(2)它會在第1768-1775行讀取web.xml中的<display-name>元素,如果有,則從內容中去掉。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542115547-1.png" title="2.png" />
(3)它會在第1778-1785行擷取web.xml的版本,因為web.xml對應的XML schema有好幾個版本了,有2.3,現在2.4,2.5了,對應的版本資訊不同,我們在其中新增內容的結構和方式也會有差異,所以這個資訊也很重要,這個資訊會從根項目的version屬性獲得,我們得到我們的web.xml 版本是2.4
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/154211B47-2.png" title="3.png" />
(4)因為我們是updateWebXml方法,所以它必定對xml內容進行了改變,所以xml的內容必須從多個渠道收集,首先它在第1789行通過getExtraContent()獲得了我們要對原始的xml進行改變的額外內容,這些內容會從許多途徑收集完成,我們將其作為我們要加工的原始內容。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542116128-3.png" title="4.png" />
關於這一點非常複雜, 我準備放在“精華疑點解答”中。
(5)有了(4)產生的額外內容後,我們開始對這段內容進行加工。我們建立了一個newContent字串,用於儲存加工後的新字串,它的初始值是在最老版本的來自war包的web.xml中,在</web-app> 的上面吧額外的那段內容也就是(4)返回的extraContent)添加上進去。換句話說,它就是添加到web.xml的尾部。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542112244-4.png" title="5.png" />
(6)然後在(5)的基礎上,在1798-1802行把老的包名替換為新的包名:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542112N1-5.png" title="6.png" />
(7)接著在1806-1808行它會去建立並且更新liferay-web.xml,這個只對於web.xml版本高於2.3適用,它的主要作用是吧我們的web.xml拆分內容存於newContent中),吧其中所有的過濾器(除了Invoker Filter)全部移到liferay-web.xml中,然後把剩下的部分加上Invoker Filter再反退給並且儲存在newContent中具體的細節我會在“精華疑點解答”中給出。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542116129-6.png" title="7.png" />
(8)最後在第1812-1814行吧返回的newContent的內容更新到web.xml檔案中。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542115443-7.png" title="8.png" />
精華疑點解答1:
(1)在構建新的web.xml內容時候,原始素材來自於getExtraContent()的方法調用,這個方法調用後到底加了哪些額外內容呢?為此我們進入getExtraContent()方法的調試。
首先我們看到在第122行它會調用超類的getExtraContent()方法來擷取額外內容,要改變的內容都存放在變數StringBundler sb中。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542111H1-8.png" title="9.png" />
不具體展開了,從父類的getExtraContent方法返回的內容如下:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542112128-9.png" title="10.png" />
整體上看,加了以下內容:
(1)加了1個listener(SerializableSessionAttributeListener),
(2)加了1個Servlet(SetPortletClassLoaderServlet),並且這個Servlet的load-on-startup為0
(3)加了若干標記庫定義,如果高於web.xml版本高於2.3,則放在<jsp-config>元素下,如果版本低於2.3,那麼直接放在根項目下。
這些標記庫包括:aui.tld,liferay-portlet.tld,liferay-portlet-ext.tld,liferay-security.tld,liferay-theme.tld,liferay-ui.tld,liferay-util.tld
回想我們上次研究的內容,這些對應的tld檔案都會從portalImpl.jar中複製到對應的/WEB-INF/tld檔案下,所以使用這些標記庫中的標記都沒問題。
(4)加了1個filter(PortalClassLoaderFilter),並且它會利用CompoundSessionIdFilter過濾器,它的url-pattern是任意請求 /*
然後第127行-135行是對於webSphere伺服器,加一段伺服器特有的配置到StringBundler中,因為我們伺服器用的是tomcat,所以不考慮這段代碼。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/154211FL-10.png" title="11.png" />
然後第142行會調用updatePortletXML方法,入參也是從我們部署時的portlet war包中解壓出來的portlet.xml檔案。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/154211G27-11.png" title="12.png" />
從上面看出,它其實就是讀取portlet.xml內容,然後把其中的JSPPortlet轉為MVCPortlet,因為我們的portlet.xml沒有,所以原樣返回。
然後在第144行調用sb.append(getServletContent(portletXML,webXML))來附加上和Servlet配置相關的內容到StringBundler中。我們來看下getServletContent的實現核心):
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542114431-12.png" title="13.png" />
可以發現,它先會讀取portlet.xml檔案,然後對於其中的每個<portlet> 進行迭代,建立1段servlet定義。具體看就是定義一個servlet叫PortletServlet, 這個servlet有個初始參數portlet-class為我們當前Portlet的類名,並且load-on-startup為1,而且它的url-mapping是對於任意請求。然後web.xml檔案,然後對於其中的<servlet>進行迭代,因為我們檔案中沒有。<servlet>定義,所以直接跳過。所以最後從getServletContent(portletXML,webXML)中返回到getExtraContent()後的資訊就只有一段PortletServlet的定義。
然後從第146行它會去處理jsf檔案,因為我們沒有faces-config.xml,所以不做任何處理。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542112264-13.png" title="14.png" />
然後在第148行會判斷,如果是sun的jsfPortlet,那麼會加上一段特殊配置到StringBundler中,因為我們不是用的SunJSFPortlet, 所以跳過:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542111250-14.png" title="15.png" />
然後第162-166行加上一段PortletContextListener監聽器到StringBundler中:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/15421154T-15.png" title="16.png" />
然後第170行會會加上一組ignore過濾器到StringBundler中,它們用於當Portal類載入時候吧一些指定副檔名的檔案過濾掉。這組過濾器的定義通過方法getIgnoreFiltersContent(srcFile)擷取:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/154211B04-16.png" title="17.png" />
事實上,通過調試,他們都來自於portal-impl.jar檔案:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/15421153a-17.png" title="18.png" />
然後第174行會加上一組用於加速請求處理的過濾器到StringBundler中,它們用於當Portal類載入時候做一些加速處理,比如緩衝,比如壓縮。這組過濾器的定義通過方法getSpeedFiltersContent(srcFile)擷取:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542112K6-18.png" title="19.png" />
事實上,通過調試,他們也都來自於portal-impl.jar檔案:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542111F6-19.png" title="20.png" />
最後,在第178行加上一組ServletContextInclude的過濾器到StringBundler中:
650) this.width=650;" src="http://img1.51cto.com/attachment/201309/134627370.png" title="21.png" />
這方法調用後加上了以下內容:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542113920-21.png" title="22.png" />
所以最後StringBundler中的內容返回後就是上述各種內容的總和。
精華疑點解答2:
在updateLiferayWebXml方法中到底更新了什麼內容給liferay-web.xml,並且返回的剩餘內容是什麼呢?為此我們也進行調試.
我們發現,首先,它利用WebXMLBuilder吧我們傳入的由getExtraContent參合進去的總的web.xml內容檔案先格式化,包括元素縮排以及各個元素的排列順序。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542115212-22.png" title="23.png" />
然後,它擷取這段內容中從第一個<filter>到最後一個<filter-mapping>這一整段關於過濾器的定義的字串,把座標上下界分別存放到變數x,y中,然後把這段過濾器內容存放到filterContent字串變數中:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542111004-23.png" title="24.png" />
接下來,它會先建立一個<web-app>元素,然後把剛才的關於過濾器的全部定義插入到這個<web-app>元素內,利用WebXMLBuilder對格式重新組織下,最後將其內容寫入部署緩衝目錄的/WEB-INF/liferay-web.xml中。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/154211A29-24.png" title="25.png" />
我們對比下檔案系統的檔案時間戳記,果然這個部署緩衝目錄下的liferay-web.xml是剛更新的。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542116044-25.png" title="26.png" />
接下來就是對liferay-web.xml之外的部分進行處理了:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542111148-26.png" title="27.png" />
可以看出,它先把web.xml中所有關於過濾器的部分去掉,然後中間填上InvokerFilter過濾器的定義部分,這部分是利用API getInvokerFilterContent()方法調用獲得的。這樣就形成了最終的web.xml,其實也很好理解,因為避免重複定義,所以web.xml中只保留了InvokerFilter,而其他的filter都放在了liferay-web.xml中。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/1542116460-27.png" title="28.png" />
這裡從右邊調試資訊可以很明顯的看出,現在的<filter>部分只有Invoker Filter而沒有其他部分了。
我們從檔案系統看,也可以看出這個web.xml的確是剛才產生的。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/15421134T-28.png" title="29.png" />
總結:
以上這個過程太複雜了,我們有太多的發現和太多的知識需要總結了。
(1)updateWebXml不僅包含更新web.xml,還包括建立更新liferay-web.xml
(2)在建立更新web.xml時,它總有一個原始xml字串供我們處理,這原始的web.xml字串是由從我們war包中擷取的web.xml內容的全部加上一些額外內容形成的。
(3)這些額外的內容由多個渠道擷取的內容拼湊而成,並且封裝在getExtraContent()方法中,具體來說,它包含下述內容:
a.加了1個listener(SerializableSessionAttributeListener),
b.加了1個Servlet(SetPortletClassLoaderServlet),並且這個Servlet的load-on-startup為0
c.加了若干標記庫定義,如果高於web.xml版本高於2.3,則放在<jsp-config>元素下,如果版本低於2.3,那麼直接放在根項目下。
這些標記庫包括:aui.tld,liferay-portlet.tld,liferay-portlet-ext.tld,liferay-security.tld,liferay-theme.tld,liferay-ui.tld,liferay-util.tld
d.加了1個filter(PortalClassLoaderFilter),並且它會利用CompoundSessionIdFilter過濾器,它的url-pattern是任意請求 /*
e.如果伺服器類型是websphere,則加一段和websphere有關的特殊初始上下文<context-param>
f. 加一段PortletServlet的定義
g.如果是JSFPortlet,則加上一段特殊的listener.
h.加一段PortletContextListener監聽器定義
i.加若干 Ignore Filter過濾器,它們都來自portal-impl.jar中。
j.加若干 Speed Filter過濾器,它們都來自portal-impl.jar中。
k.加上ServletContextInclude過濾器。
(4)再把(3)的額外內容附加到原始的web.xml後,我們就對新的web.xml的內容進行後處理,處理的要點是吧這個web.xml的內容拆分為2個xml檔案,一個是web.xml,一個是liferay-web.xml檔案。這2個檔案的根項目都是<web-app>,不同在於liferay-web.xml檔案中包含了所有的過濾器,而web.xml中則是剩下的元素去除所有的一般過濾器,但是加上了Invoker Filter過濾器,這樣可以起到“分而治之”的作用。
(5)最後會吧這些資源檔都複製到tomcat/webapps下的相應應用的部署目錄下。
本文出自 “平行線的凝聚” 部落格,請務必保留此出處http://supercharles888.blog.51cto.com/609344/1286976