ПОСЛЕ обновления от весенней загрузки 1.2 до 1.5.2, FileNotFoundException во время запуска Tomcat 8.5

Я обновил Spring Boot с 1.2.0 до 1.5.2.

После этого обновления Tomcat 8.5 создает исключение FileNotFoundException при запуске.

Ниже приведено одно из тех исключений, которое вызывает более ~10 подобных исключений.

Я понятия не имею о назначении этих банок, другими словами, я не добавил <dependency> для этих баночек в pom.xml.

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)

Любая помощь будет оценена.

4 ответа

Решение

Первопричина:

Согласно Tomcat Wiki, спецификация Servlet 3.0 требует сканирования Jar во время запуска сервера.

Tomcat использует org.apache.tomcat.util.scan. StandardJarScanner для этой цели.

Из Javadoc StandardJarScanner.

Реализация 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 (без загрузки).

Решение 2: Весна специфическая

Вы можете отключить 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.

Просто для того, чтобы улучшить выводы Sundaraj... полное отключение сканирования TLD нарушит поддержку JSP/JSTL.

Проблема в том, что с самим classpath все в порядке, только 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);
      }
    };
  }

JarScannerFactory загрузил StandardJarScanner, который нам нужно здесь настроить, так что это (для весенней загрузки 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);
                }}
        );
    }
}

Для меня это работает после того, как я добавлю в

tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\

*.jar

В каталоге.Свойства.

Другие вопросы по тегам