Liferay 部署war包中deployDirectory过程中调用updateWebXml()方法详细分析

简介:

引入:

在上文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 中。


(2)它会在第1768-1775行读取web.xml中的<display-name>元素,如果有,则从内容中去掉。


(3)它会在第1778-1785行获取web.xml的版本,因为web.xml对应的XML schema有好几个版本了,有2.3,现在2.4,2.5了,对应的版本信息不同,我们在其中添加内容的结构和方式也会有差异,所以这个信息也很重要,这个信息会从根元素的version属性获得,我们得到我们的web.xml 版本是2.4


(4)因为我们是updateWebXml方法,所以它必定对xml内容进行了改变,所以xml的内容必须从多个渠道收集,首先它在第1789行通过getExtraContent()获得了我们要对原始的xml进行改变的额外内容,这些内容会从许多途径收集完成,我们将其作为我们要加工的原始内容。

关于这一点非常复杂, 我准备放在“精华疑点解答”中。


(5)有了(4)产生的额外内容后,我们开始对这段内容进行加工。我们新建了一个newContent字符串,用于存储加工后的新字符串,它的初始值是在最老版本的来自war包的web.xml中,</web-app> 的上面吧额外的那段内容(也就是(4)返回的extraContent)添加上进去。换句话说,它就是添加到web.xml的尾部。


(6)然后在(5)的基础上,在1798-1802行把老的包名替换为新的包名:


(7)接着在1806-1808行它会去创建并且更新liferay-web.xml,这个只对于web.xml版本高于2.3适用,它的主要作用是吧我们的web.xml拆分(内容存于newContent中),吧其中所有的过滤器(除了Invoker Filter)全部移到liferay-web.xml中,然后把剩下的部分加上Invoker Filter再反退给并且保存在newContent中具体的细节我会在“精华疑点解答”中给出。


(8)最后在第1812-1814行吧返回的newContent的内容更新到web.xml文件中。



精华疑点解答1:

(1)在构建新的web.xml内容时候,原始素材来自于getExtraContent()的方法调用,这个方法调用后到底加了哪些额外内容呢?为此我们进入getExtraContent()方法的调试。


首先我们看到在第122行它会调用超类的getExtraContent()方法来获取额外内容,要改变的内容都存放在变量StringBundler sb中。

不具体展开了,从父类的getExtraContent方法返回的内容如下:

整体上看,加了以下内容:

(1)加了1listener(SerializableSessionAttributeListener),

(2)加了1Servlet(SetPortletClassLoaderServlet),并且这个Servletload-on-startup0

(3)加了若干标记库定义,如果高于web.xml版本高于2.3,则放在<jsp-config>元素下,如果版本低于2.3,那么直接放在根元素下。

这些标记库包括:aui.tldliferay-portlet.tldliferay-portlet-ext.tldliferay-security.tldliferay-theme.tldliferay-ui.tldliferay-util.tld

回想我们上次研究的内容,这些对应的tld文件都会从portalImpl.jar中复制到对应的/WEB-INF/tld文件下,所以使用这些标记库中的标记都没问题。

(4)加了1filter(PortalClassLoaderFilter),并且它会利用CompoundSessionIdFilter过滤器,它的url-pattern是任意请求 /*


然后第127-135行是对于webSphere服务器,加一段服务器特有的配置到StringBundler中,因为我们服务器用的是tomcat,所以不考虑这段代码。


然后第142行会调用updatePortletXML方法,入参也是从我们部署时的portlet war包中解压出来的portlet.xml文件。

从上面看出,它其实就是读取portlet.xml内容,然后把其中的JSPPortlet转为MVCPortlet,因为我们的portlet.xml没有,所以原样返回。


然后在第144行调用sb.append(getServletContent(portletXML,webXML))来附加上和Servlet配置相关的内容到StringBundler中。我们来看下getServletContent的实现(核心)

可以发现,它先会读取portlet.xml文件,然后对于其中的每个<portlet> 进行迭代,创建1servlet定义。具体看就是定义一个servletPortletServlet, 这个servlet有个初始参数portlet-class为我们当前Portlet的类名,并且load-on-startup1,而且它的url-mapping是对于任意请求。然后web.xml文件,然后对于其中的<servlet>进行迭代,因为我们文件中没有。<servlet>定义,所以直接跳过。所以最后从getServletContent(portletXML,webXML)中返回到getExtraContent()后的信息就只有一段PortletServlet的定义。


然后从第146行它会去处理jsf文件,因为我们没有faces-config.xml,所以不做任何处理。


然后在第148行会判断,如果是sunjsfPortlet,那么会加上一段特殊配置到StringBundler中,因为我们不是用的SunJSFPortlet, 所以跳过:


然后第162-166行加上一段PortletContextListener监听器到StringBundler中:


然后第170行会会加上一组ignore过滤器到StringBundler中,它们用于当Portal类加载时候吧一些指定扩展名的文件过滤掉。这组过滤器的定义通过方法getIgnoreFiltersContent(srcFile)获取:

事实上,通过调试,他们都来自于portal-impl.jar文件:


然后第174行会加上一组用于加速请求处理的过滤器到StringBundler中,它们用于当Portal类加载时候做一些加速处理,比如缓存,比如压缩。这组过滤器的定义通过方法getSpeedFiltersContent(srcFile)获取:

事实上,通过调试,他们也都来自于portal-impl.jar文件:


最后,在第178行加上一组ServletContextInclude的过滤器到StringBundler中:

这方法调用后加上了以下内容:


所以最后StringBundler中的内容返回后就是上述各种内容的总和。


精华疑点解答2:

在updateLiferayWebXml方法中到底更新了什么内容给liferay-web.xml,并且返回的剩余内容是什么呢?为此我们也进行调试.

我们发现,首先,它利用WebXMLBuilder吧我们传入的由getExtraContent参合进去的总的web.xml内容文件先格式化,包括元素缩进以及各个元素的排列顺序。


然后,它获取这段内容中从第一个<filter>到最后一个<filter-mapping>这一整段关于过滤器的定义的字符串,把坐标上下界分别存放到变量x,y中,然后把这段过滤器内容存放到filterContent字符串变量中:


接下来,它会先创建一个<web-app>元素,然后把刚才的关于过滤器的全部定义插入到这个<web-app>元素内,利用WebXMLBuilder对格式重新组织下,最后将其内容写入部署缓存目录的/WEB-INF/liferay-web.xml中。


我们对比下文件系统的文件时间戳,果然这个部署缓存目录下的liferay-web.xml是刚更新的。


接下来就是对liferay-web.xml之外的部分进行处理了:

可以看出,它先把web.xml中所有关于过滤器的部分去掉,然后中间填上InvokerFilter过滤器的定义部分,这部分是利用API getInvokerFilterContent()方法调用获得的。这样就形成了最终的web.xml,其实也很好理解,因为避免重复定义,所以web.xml中只保留了InvokerFilter,而其他的filter都放在了liferay-web.xml中。

这里从右边调试信息可以很明显的看出,现在的<filter>部分只有Invoker Filter而没有其他部分了。

我们从文件系统看,也可以看出这个web.xml的确是刚才生成的。


总结:

以上这个过程太复杂了,我们有太多的发现和太多的知识需要总结了。

(1)updateWebXml不仅包含更新web.xml,还包括创建更新liferay-web.xml

(2)在创建更新web.xml时,它总有一个原始xml字符串供我们处理,这原始的web.xml字符串是由从我们war包中获取的web.xml内容的全部加上一些额外内容形成的。

(3)这些额外的内容由多个渠道获取的内容拼凑而成,并且封装在getExtraContent()方法中,具体来说,它包含下述内容:

a.加了1listener(SerializableSessionAttributeListener),

b.加了1Servlet(SetPortletClassLoaderServlet),并且这个Servletload-on-startup0

c.加了若干标记库定义,如果高于web.xml版本高于2.3,则放在<jsp-config>元素下,如果版本低于2.3,那么直接放在根元素下。

这些标记库包括:aui.tldliferay-portlet.tldliferay-portlet-ext.tldliferay-security.tldliferay-theme.tldliferay-ui.tldliferay-util.tld

d.加了1filter(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下的相应应用的部署目录下。






本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1286976,如需转载请自行联系原作者
目录
相关文章
|
3月前
|
Java Linux Maven
java依赖冲突解决问题之容器加载依赖jar包如何解决
java依赖冲突解决问题之容器加载依赖jar包如何解决
|
2月前
|
设计模式 人工智能 安全
【Tomcat源码分析】生命周期机制 Lifecycle
Tomcat内部通过各种组件协同工作,构建了一个复杂的Web服务器架构。其中,`Lifecycle`机制作为核心,管理组件从创建到销毁的整个生命周期。本文详细解析了Lifecycle的工作原理及其方法,如初始化、启动、停止和销毁等关键步骤,并展示了LifecycleBase类如何通过状态机和模板模式实现这一过程。通过深入理解Lifecycle,我们可以更好地掌握组件生命周期管理,提升系统设计能力。欢迎关注【码上遇见你】获取更多信息,或搜索【AI贝塔】体验免费的Chat GPT。希望本章内容对你有所帮助。
|
3月前
|
Java Maven
构建Springboot项目、实现简单的输出功能、将项目打包成可以执行的JAR包(详细图解过程)
这篇文章详细介绍了构建SpringBoot项目的过程,包括新建工程、选择环境配置、添加依赖、项目结构说明,并演示了如何编写一个简单的Controller控制器实现输出功能,最后讲解了如何使用Maven将项目打包成可执行的JAR包,并提供了运行JAR包的命令和测试效果。
构建Springboot项目、实现简单的输出功能、将项目打包成可以执行的JAR包(详细图解过程)
|
5月前
|
前端开发 Java 应用服务中间件
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
|
Java 应用服务中间件 容器
Tomcat原理系列之三:对请求的过程详细分析
Tomcat原理系列之三:对请求的过程详细分析
Tomcat原理系列之三:对请求的过程详细分析
|
编译器 C++ Windows
Qt程序运行依赖环境打包方法:windeployqt方法
3分钟学会Qt程序运行依赖环境打包方法:windeployqt方法!
456 0
Qt程序运行依赖环境打包方法:windeployqt方法
环境变量加载流程原理介绍
环境变量加载流程原理介绍
118 0
环境变量加载流程原理介绍
|
SQL Java 关系型数据库
JavaWeb常用工具类以及Jar包总结(后续不断补充)
JavaWeb常用工具类以及Jar包总结(后续不断补充)
|
Apache Java 应用服务中间件
|
Java Spring 缓存
Java项目启动时执行指定方法的几种方式
版权声明:本文为博主原创文章,未经博主允许不得转载。博客源地址为zhixiang.org.cn https://blog.csdn.net/myFirstCN/article/details/81750854 很多时候我们都会碰到需要在程序启动时去执行的方法,比如说去读取某个配置,预加载缓存,定时任务的初始化等。
2718 0