在从Spring Boot 1.2升级到1.5.2之后,在Tomcat 8.5启动期间出现FileNotFoundException错误。

29

我将Spring Boot从1.2.0升级到了1.5.2。

在升级后,Tomcat 8.5启动时抛出了FileNotFoundException异常。

以下是其中的一个异常,它抛出了多达10个左右类似的异常。

对于这些jar的用途,我一无所知,换句话说,在pom.xml中我没有添加这些jar的dependency。

INFO: Starting Servlet Engine: Apache Tomcat/8.5.11
Apr 06, 2017 3:53:57 PM org.apache.tomcat.util.scan.StandardJarScanner scan
WARNING: Failed to scan [file:/C:/Users/myname/.m2/repository/com/sun/xml/ws/jaxws-rt/2.1.7/jaxws-api.jar] from classloader hierarchy
java.io.FileNotFoundException: C:\Users\myname\.m2\repository\com\sun\xml\ws\jaxws-rt\2.1.7\jaxws-api.jar (The system cannot find the file specified)
    at java.util.zip.ZipFile.open(Native Method)
    at java.util.zip.ZipFile.<init>(ZipFile.java:219)
    at java.util.zip.ZipFile.<init>(ZipFile.java:149)
    at java.util.jar.JarFile.<init>(JarFile.java:166)
    at java.util.jar.JarFile.<init>(JarFile.java:130)
    at org.apache.tomcat.util.scan.JarFileUrlJar.<init>(JarFileUrlJar.java:60)
    at org.apache.tomcat.util.scan.JarFactory.newInstance(JarFactory.java:48)
    at org.apache.tomcat.util.scan.StandardJarScanner.process(StandardJarScanner.java:338)
    at org.apache.tomcat.util.scan.StandardJarScanner.scan(StandardJarScanner.java:288)
    at org.apache.jasper.servlet.TldScanner.scanJars(TldScanner.java:262)
    at org.apache.jasper.servlet.TldScanner.scan(TldScanner.java:104)
    at org.apache.jasper.servlet.JasperInitializer.onStartup(JasperInitializer.java:101)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5178)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

任何帮助都将不胜感激。


@AntonNovopashin,感谢您的回复,我已经解决了这个错误并将解决方案记录为答案。 - Sundararaj Govindasamy
4个回答

43

根本原因:

根据Tomcat Wiki所述,Servlet 3.0规范要求在服务器启动期间进行Jar扫描。

Tomcat使用org.apache.tomcat.util.scan.StandardJarScanner来实现这个功能。

StandardJarScanner的Javadoc中得知:

默认的JarScanner实现扫描WEB-INF/lib目录, 然后扫描提供的类装入器, 最后沿着类装入器层次结构工作。此实现足以满足Servlet 3.0规范的要求,并提供了许多Tomcat特定的扩展,这些扩展包括:

  • 扫描类装入器层次结构(默认启用)测试所有文件以查看它们是否为JAR文件(默认禁用)

  • 测试所有目录以查看它们是否为已解压缩的JAR文件(默认禁用)

  • 所有扩展都可以通过配置进行控制

解决方案1:Spring Boot特定。

我们可以禁用这个Jar扫描功能。

我通过在application-xxx.properties文件中添加以下属性来禁用它。此属性是Spring Boot特有的

# Comma-separated list of additional patterns that match jars to ignore for TLD scanning.    
server.tomcat.additional-tld-skip-patterns=*.jar

您可以在这里找到来自Tomcat的类似属性 链接.

这些属性可用于配置传统Tomcat(非Spring Boot)应用程序。

解决方案2:Spring特定

您可以按如下所示禁用JarScanner 清单文件。

@Bean
public EmbeddedServletContainerFactory embeddedServletContainerFactory() {
  return new TomcatEmbeddedServletContainerFactory() {
    @Override
    protected void postProcessContext(Context context) {
      ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
    }
  };
}

方案3:传统独立Tomcat:

<Context>
  ...
  <JarScanner scanManifest="false"/>
  ...
</Context>

参考:Jar Scanner 组件


4
既然这些文件是JDK的一部分,为什么会扫描Maven仓库呢?禁用可以解决问题,但它不应该在那里搜索这些jar文件吗? - TheBakker
1
太好了。帮助我找到了问题所在。在我的情况下,我将特定的jar文件过滤为逗号分隔的列表:server.tomcat.additional-tld-skip-patterns=oraclepki.jar,osdt_core.jar,osdt_cert.jar - Apple Pirate
如果您的JSP文件中有标签库,那么这些解决方案是否好用?该jar文件将不会包含在您的运行时中。 - Aerox

18

为了改善Sundaraj所发现的问题...完全禁用TLD扫描会破坏 JSP/JSTL支持。

问题在于类路径本身没有问题,只有Tomcat 额外地 扫描了每个Jar包的清单文件,而由于使用Maven每个Jar都在自己的目录中,这将产生无意义的路径(可能是从Eclipse运行的?)。

因此,如果您想继续使用JSP和JSTL,则应仅禁用清单扫描。

对于Spring Boot 2.0,请将以下内容添加到您的应用程序配置中:

  @Bean
  public TomcatServletWebServerFactory tomcatFactory() {
    return new TomcatServletWebServerFactory() {
      @Override
      protected void postProcessContext(Context context) {
        ((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
      }
    };
  }

可能这就是为什么我们需要将 tld 文件添加到类路径中的原因 ;) - Neill
@rustyx 你好,你的解决方案也会破坏 JSTL 的支持,实际上 - 我的帖子 链接 - Johnczek
在我的环境中,使用Spring Boot 2.4.1是可行的。 - scriptfoo

1

JarScannerFactory 已加载 StandardJarScanner,我们需要在此处进行配置,以便(对于Spring Boot 2.1.8)也能正常工作。

import org.apache.tomcat.JarScanner;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebContextConfiguration {

    @Bean
    public ServletContextInitializer servletContextInitializer() {
        return context -> context.setAttribute(
                JarScanner.class.getName(),
                new StandardJarScanner() {{
                    setScanManifest(false);
                }}
        );
    }
}

0

对我来说,在我添加到之后它可以工作

tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\

*.jar

catalina.properties 中。


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