【问题标题】:AFTER upgrade from Spring boot 1.2 to 1.5.2, FileNotFoundException during Tomcat 8.5 Startup从 Spring boot 1.2 升级到 1.5.2 后,Tomcat 8.5 启动期间出现 FileNotFoundException
【发布时间】:2017-09-02 01:22:27
【问题描述】:

升级了 Spring Boot 从 1.2.0 到 1.5.2

升级后,Tomcat 8.5启动期间抛出FileNotFoundException

下面是其中一个异常,它抛出了超过~10个类似的异常。

我不知道这些jar的用途,换句话说,我没有在pom.xml中为这些jar添加<dependency> p>

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,感谢您的回复,我解决了这个错误并将解决方案记录为答案。

标签: spring spring-boot tomcat8.5


【解决方案1】:

根本原因:

根据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 specific

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

您可以在 Tomcat 中找到类似的属性 here

这些属性可用于配置传统 tomcat(-spring boot)应用程序。

解决方案 2:特定于 Spring

您可以为 ma​​nifest 文件禁用 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>

参考:The Jar Scanner Component.

【讨论】:

  • 但是既然这些是 JDK 的一部分,为什么要扫描 maven 存储库来寻找它们呢?禁用作品,但它不应该在他们的 jar 中搜索那些 jar 吗?
  • 太棒了。帮助我识别问题。在我的情况下,我将特定的 jar 过滤为逗号分隔的列表: server.tomcat.additional-tld-skip-patterns=oraclepki.jar,osdt_core.jar,osdt_cert.jar
  • 如果您的 JSP 文件中有标签库,这些解决方案是否很好? jar 不会包含在您的运行时中。
【解决方案2】:

只是为了改进 Sundaraj 的发现...完全禁用 TLD 扫描会破坏 JSP/JSTL 支持。

问题是类路径本身没问题,只有 Tomcat 另外扫描每个 Jar 的 manifest 文件,而且由于使用 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 文件添加到类路径中;)
  • @rustyx 你好,你的解决方案实际上也会破坏 jstl 支持 - 我的线程 link
  • 适用于我的 Spring Boot 2.4.1。
【解决方案3】:

JarScannerFactory loaded StandardJarScanner,我们需要配置 here,所以这个(对于 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);
                }}
        );
    }
}

【讨论】:

    猜你喜欢
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多