0%

Jenkins持续集成发布时tomcat不能删除目录下文件

使用jenkins自动发布到tomcat时遇到一个问题,发布的时候不能自动删除tomcat下的工程目录,必须关闭tomcat之后,才能删除;提示如下

1
"org.codehaus.cargo.container.tomcat.internal.TomcatManagerException: The Tomcat Manager responded "FAIL - Unable to delete [C:\ths\Tomcat8082-alk\webapps\SuperStation]. The continued presence of this file may cause problems."

jenkins

解决方法

元素中增加一个属性antiResourceLocking=”true” antiJARLocking=”true”,默认是”false”。

1
<Context reloadable="true" antiJARLocking="true" antiResourceLocking="true">

实际上,这两个参数就是配置Tomcat的资源锁定和Jar包锁定策略。

antiJARLocking

先来看看应用的antiJARLocking属性设置为true时,Tomcat是怎么处理的。
针对antiJARLocking属性的处理集中在WebappClassLoader的getResource和findResourceInternal方法里,主要原理是将包含在Jar包里的资源抽取放到应用的工作目录(work里应用对应的目录)下去。
把这个属性设置为true之后,部署应用就可以在work\Catalina\localhost\struts2-blank\loader目录下看到被解压的Jar包内容。
antiJARLocking属性在有的时候并不会生效,从WebappClassLoader的getResource和findResource方法逻辑里可以看出一些端倪,在一些情况下(通过对Loader的delegate、searchExternalFirst等相关属性进行配置),资源的获取并不是WebappClassLoader去做的,而是其父加载器的getResource方法或父类的findResource方法去做的,WebappClassLoader的父类是URLClassLoader、父加载器是URLClassLoader实例。

antiResourceLocking

当antiResourceLocking设置为true的时候,Tomcat不会锁定应用下的任何文件。那Tomcat是怎么做到这一点的呢?
在Tomcat的架构里,应用也是一个级别的容器,对应的接口是Context;各级容器本身都具备生命周期,而且配置了多个生命周期监听器来监听容器不同的生命周期过程。Tomcat在初始化的时候,给Context增加了一个生命周期监听器org.apache.catalina.startup.ContextConfig;然后在Context真正开始启动之前,会有一个BEFORE_START_EVENT状态,ContextConfig监听到这个状态的事件后,就会针对antiResourceLocking进行处理。
总结一下,就是如果应用的antiResourceLocking属性设置为true,就将应用的doc base移到临时目录下,让Tomca不会占用webapps下的文件。Tomcat里java.io.tmpdir默认指向Tomcat的temp目录。

副作用

从上面的分析来看,antiResourceLocking为true有几个副作用:

  1. 会延长应用的启动时间,因为多了临时目录的清理和往临时目录拷贝应用内容的操作;
  2. 如果不知道这个属性的原理,修改webapps下应用的JSP,那就不会动态重加载到新的页面内容了,因为应用的doc base已经不再在webapps下了;
  3. 停止Tomcat的时候,临时目录下实际的doc base会被删掉,
    结合第二条和第三条,如果要修改应用的JSP,那必须将改动同时拷贝到两个目录下(原始doc base和临时目录下的doc base)。
    所以Tomcat里这个属性缺省为false。在使用Tomcat 6.0.24之前的版本时,如果要用这个属性解决文件被锁的问题,三思而行。

参考链接:http://blog.csdn.net/yanjun008/article/details/41249753