ПОСЛЕ обновления от весенней загрузки 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
В каталоге.Свойства.