引入:

在Liferay中部署portlet其细节远比向tomcat部署一个web应用那么简单,这文章就来展示下其中的奥秘。



分析:

在这个动作发生后,它会被容器的PortletAutoDeployerListener所捕捉,从而进入到deploy()方法中:

Liferay 中部署portlet的细节窥探_第1张图片

我们可以看到,第43行它其实会去打开这个压缩文件然后比较器结构是否为portlet的xml文件结构,因为满足,所以我们这里执行到第46行,换句话说,我们的部署器(deployer)使用的是 PortletAutoDeployer的实例。


然后会走到第24行,它封装了用PortletAutoDeployer来部署我们的war包的细节:

121223281.png

它会去委托PortletAutoDeployer的deployFile(file,context)方法:


首先,在712行,它会去读写war包中的liferay-plugin-package.xml文件:

Liferay 中部署portlet的细节窥探_第2张图片

吧读来的内容存放在类PluginPackage的实例中:



然后它在第742行来判断当前war包版本(从pluginpackage中读来)是否被目标Liferay容器支持,不支持就抛出一个异常:

Liferay 中部署portlet的细节窥探_第3张图片

这里,显然是支持的,所以跳过这段代码:


然后第751-763行会从pluginPackage中获取推荐的上下文名称,我们这里获得的是logsearchportlet,并且设置给pluginPackage的context属性,最后更新PluginPackage。

Liferay 中部署portlet的细节窥探_第4张图片


接下来会构造部署目录deployDir路径

Liferay 中部署portlet的细节窥探_第5张图片


如上所示,在第765行,如果displayName不为null,则在后面加上.war:


然后来根据服务器类型来对部署目录(deployDir)的名字进行进一步处理:

Liferay 中部署portlet的细节窥探_第6张图片

这里可以看出,如果appServer类型是jboss比较特殊点,但是我们不是jboss,而是tomcat,而且我们unpackWar是true(表明我们要打开这个war包),所以我们的部署目录是在刚才的deployDir的路径基础上去掉最后4个字符,也就是吧.war去掉,所以在第786行之前,现在的deployDir和displayName的值一摸一样,因为加上了.war又去掉了.war了。


所以,我们在786行吧部署的目标目录加载这个部署目录相对路径之前,就得到了部署目录的绝对路径,果然和我们预期是一致的。

Liferay 中部署portlet的细节窥探_第7张图片


接下来,我们就在788行构造一个File对象指向这个部署目录,然后进行文件的生成,复制等操作。


最终会调用deployFile来部署war包到刚才生成的指定部署目录下:

Liferay 中部署portlet的细节窥探_第8张图片

我们来看下它的实现;


撇开一些不重要的东西,我们直接跳到deployFile的第883行,首先可以发现它在$CATALINA_HOME/temp目录下以时间戳为文件名创建了一个临时目录,这个目录用于部署过程的临时目录,然后在887行,吧我们的war文件展开到这个temp目录下:

Liferay 中部署portlet的细节窥探_第9张图片


其中,当调用887行的时候,服务器会打印出一条日志表明这个展开的io操作正在进行

Expanding xxx into xxx/temp/


然后在第888行,我们调用deployDirectory方法来完成具体的部署目录方法,这步骤非常复杂,具体的过程我会在下面一文章中详细介绍,总体来说作用是具体的往部署目录中加入指定的文件,配置等:

Liferay 中部署portlet的细节窥探_第10张图片


最后在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吧临时目录中的内容加工后复制到最终部署目录的细节,因为太复杂, 所以我想用一篇新的文章分析。