为什么Tomcat会对已存在的JAR文件抛出FileNotFoundException异常?

7

我想知道是什么原因导致Tomcat或者Java的原生ZipFile.open方法声明文件不存在,而实际上它确实存在?这个问题已经阻碍了我的工作一个月。在尝试运行tomcat7-maven-plugin时会出现这种情况。它在大多数机器上都可以正常工作,包括我的机器(OSX),但是却在我们的构建服务器(LINUX)和我的一个同事的电脑上(OSX,与我的笔记本电脑型号相同)失败了。以下是在Maven构建中看到的错误:

[INFO] --- tomcat7-maven-plugin:2.2:run (start-tomcat) @ PROJECT ---
[INFO] Running war on http://localhost:8080/contentmain
[INFO] Using existing Tomcat server configuration at
/WORKSPACE/PROJECT/tomcat7
Feb 05, 2015 11:17:53 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal
performance in production environments was not found on the
java.library.path:
/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
Feb 05, 2015 11:17:54 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Feb 05, 2015 11:17:54 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Feb 05, 2015 11:17:54 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8443"]
Feb 05, 2015 11:17:54 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 651 ms
Feb 05, 2015 11:17:54 PM org.apache.catalina.core.StandardService
startInternal
INFO: Starting service Catalina
Feb 05, 2015 11:17:54 PM org.apache.catalina.core.StandardEngine
startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.53
Feb 05, 2015 11:17:54 PM org.apache.tomcat.util.scan.StandardJarScanner
scan
WARNING: Failed to scan JAR
[file:/WORKSPACE/tomcat7/webapps/../../target/PROJECT/WEB-INF/lib/openws-1.
5.1.jar] from WEB-INF/lib
java.io.FileNotFoundException:
/WORKSPACE/PROJECT/tomcat7/webapps/../../target/PROJECT/WEB-INF/lib/openws-
1.5.1.jar (No such file or directory)
    at java.util.zip.ZipFile.open(Native Method)
    at java.util.zip.ZipFile.<init>(ZipFile.java:215)
    at java.util.zip.ZipFile.<init>(ZipFile.java:145)
    at java.util.jar.JarFile.<init>(JarFile.java:154)
    at java.util.jar.JarFile.<init>(JarFile.java:91)
    at sun.net.www.protocol.jar.URLJarFile.<init>(URLJarFile.java:93)
    at sun.net.www.protocol.jar.URLJarFile.getJarFile(URLJarFile.java:69)
    at sun.net.www.protocol.jar.JarFileFactory.get(JarFileFactory.java:99)
    at
sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:122
)
    at
sun.net.www.protocol.jar.JarURLConnection.getJarFile(JarURLConnection.java:
89)
    at org.apache.tomcat.util.scan.FileUrlJar.<init>(FileUrlJar.java:41)
    at org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:34)
    at
org.apache.catalina.startup.ContextConfig$FragmentJarScannerCallback.scan(C
ontextConfig.java:2612)
    at
org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.j
ava:259)
    at
org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java
:178)
    at
org.apache.catalina.startup.ContextConfig.processJarsForWebFragments(Contex
tConfig.java:1868)
    at
org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1256
)
    at
org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java
:873)
    at
org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java
:371)
    at
org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSuppo
rt.java:117)
    at
org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.jav
a:90)
    at
org.apache.catalina.core.StandardContext.startInternal(StandardContext.java
:5355)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at
org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1
559)
    at
org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1
549)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1
145)
    at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:
615)
    at java.lang.Thread.run(Thread.java:745)

这个错误会针对从Maven依赖中拉取的项目中的每个JAR文件重复出现。这里有数百个这样的错误。
请注意,在一个失败的机器上,我已经在ZipFile.open调用处设置了断点,并在另一个终端执行了以下操作:
cd /WORKSPACE/PROJECT/tomcat7/webapps/../../target/PROJECT/WEB-INF/lib/
ls -la

我可以确认,在调用本地的open方法并抛出声称文件不存在的异常之前,所有“丢失”的JAR文件都是存在的。这让我怀疑JAR文件可能已损坏,因此我从我的同事的机器上复制了一个失败的JAR文件,并与我在成功构建和执行后拥有的本地副本进行了比较。它们是相同的,因此“损坏的JAR”理论被排除了。
我还尝试了以下方法(没有成功):
- 缩短使用的路径(我在某个地方读到可能有256个字符的限制)。 - 将JAR文件移动到不同的目录并更改Tomcat配置以指向新位置(它们位于资源下,我将它们移动到项目base.dir下)。 - 将各种JVM堆大小从Xmx256设置为Xmx4096(我在一些帖子中读到内存问题可能会导致Tomcat声称文件丢失)。 - 删除我们通常用于Web应用程序的permgen设置。 - 将“jarScanAllDirectories”选项设置为tomcat7-maven-plugin的false或true。 - 从Apache SVN下载tomcat-maven-plugin的源代码(这包括tomcat7-maven-plugin),将其附加到Maven并通过执行进行步进调试(一切看起来都相同,直到本地ZipFile.open调用)。 - 在构建服务器上玩弄各种Jenkins作业设置(可能与此无关,因为这也在同事的机器上失败了,没有涉及Jenkins)。 - 比较我们Web应用程序使用的所有环境变量与我的同事使用的环境变量(它们是相同的)。 - 比较JDK版本(我们整个组织都标准化为1.7.0_45)。 - 比较Tomcat版本(我们在pom.xml文件中明确指定了tomcat7-maven-plugin的依赖项版本为7.0.53)。 - 等待并希望问题自行解决。 - 请求所有同事查看(这导致尝试了一些以上方法,但问题仍未解决)。
我已经快要崩溃了。我已经连续几天熬夜,只是为了让这件事情正常工作。还有什么需要注意的吗?
更新(2015年2月10日):有人建议这是由于正在运行此代码的Jenkins机器上缺少文件权限引起的。我无法访问发生问题的服务器,但我确实在那里运行了一个脚本。
echo Displaying JAR files with current permissions...
ls -la ./target/MyProject/WEB-INF/lib/

echo Adding read, write, and execute permissions to JAR files...
chmod -R 777 ./target/MyProject/WEB-INF/lib/

echo Displaying JAR files with updated permissions...
ls -la ./target/MyProject/WEB-INF/lib/

这将产生以下类似的输出结果:
[INFO] --- exec-maven-plugin:1.3.2:exec (update_jar_file_permissions) @
MyProject ---
Displaying JAR files with current permissions...
total 124556
drwxr-xr-x 2 jenkins users    20480 Feb 10 17:26 .
drwxr-xr-x 6 jenkins users     4096 Feb 10 17:26 ..
-rw-r--r-- 1 jenkins users    62983 Jan 22 00:11 activation-1.1.jar
-rw-r--r-- 1 jenkins users   351656 Jan 22 00:25 amqp-client-3.1.3.jar
-rw-r--r-- 1 jenkins users    74080 Jan 22 00:25 annotations-2.0.0.jar
-rw-r--r-- 1 jenkins users   445288 Jan 22 00:25 antlr-2.7.7.jar
-rw-r--r-- 1 jenkins users   895124 Jan 22 00:25 antlr-3.2.jar

Adding read, write, and execute permissions to JAR files...
Displaying JAR files with updated permissions...
total 124556
drwxrwxrwx 2 jenkins users    20480 Feb 10 17:26 .
drwxr-xr-x 6 jenkins users     4096 Feb 10 17:26 ..
-rwxrwxrwx 1 jenkins users    62983 Jan 22 00:11 activation-1.1.jar
-rwxrwxrwx 1 jenkins users   351656 Jan 22 00:25 amqp-client-3.1.3.jar
-rwxrwxrwx 1 jenkins users    74080 Jan 22 00:25 annotations-2.0.0.jar
-rwxrwxrwx 1 jenkins users   445288 Jan 22 00:25 antlr-2.7.7.jar
-rwxrwxrwx 1 jenkins users   895124 Jan 22 00:25 antlr-3.2.jar

正如您所看到的,存在缺失的权限问题。然而,这并没有解决问题:

Feb 10, 2015 5:27:54 PM org.apache.tomcat.util.scan.StandardJarScanner scan
WARNING: Failed to scan JAR [file:/opt/jenkins/workspace/MY_JENKINS_JOB/tomcat7/webapps/../../target/MY_PROJECT/WEB-INF/lib/activation-1.1.jar] from WEB-INF/lib
java.io.FileNotFoundException: /opt/jenkins/workspace/MY_JENKINS_JOB/tomcat7/webapps/../../target/MY_PROJECT/WEB-INF/lib/activation-1.1.jar (No such file or directory)
at java.util.zip.ZipFile.open(Native Method)

这个脚本应该在tomcat7-maven-plugin之前运行。权限应该已经设置好,JAR文件也应该可以被提取。我仍然不明白为什么这不起作用。


你的应用程序有读取JAR文件的权限吗? - Buhake Sindi
是的,谢谢您的建议。请查看我上面更新的问题。 - Alex Jansen
2
在Linux上,最后的选择是在运行Tomcat的JVM进程上运行“strace”。这将让您看到进程正在使用哪些系统调用来访问这些文件,以及出了什么问题。 - Kenster
你为什么把它放在那里,而不是放在Web应用程序内部? - user207421
@EJP,我不知道为什么我的团队把JAR文件放在那里,但这是我们的应用程序配置读取它们的目录。据我所知,这是一个非常标准的位置。 - Alex Jansen
1个回答

4
原来这不是权限问题。出于某种原因,将JAR文件从目录中复制出来再复制回去,导致它们被识别(我在某个建议中读到了这一点)。阅读cp的“man”条目,我发现它不会保留“访问控制列表(ACL)和扩展属性(EA),包括资源叉”,除非设置-p标志(使用mv时默认为on)。我猜测删除这个“访问控制”信息以某种方式使得tomcat7-maven-plugin可以访问这些文件。我不太确定问题的根本原因,但我很高兴它现在已经解决。
如果有人能够明确解释为什么这样做有效,那么我将接受那个答案,而不是这个答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接