In our application, we use JarLauncher and org.apache.catalina.startup.Tomcat (The embedded Tomcat version is 10.1.18) to launch the service, before upgrade from Spring boot 3.1.8 to 3.2.1, all worked well. Once upgraded to Spring boot 3.2.1, failed to start and reported below errors:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91)
at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53)
at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:885)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:240)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:433)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:917)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171)
at org.apache.catalina.startup.Tomcat.start(Tomcat.java:488)
at com.xxx.xxx.common.tomcat.TomcatUtils.startTomcatAndWait(TomcatUtils.java:84)
at com.xxx.xxx.xxx.Main.main(Main.java:32)
... 7 more
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: A child container failed during start
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:873)
... 16 more
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:885)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:845)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1332)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1322)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866)
... 16 more
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[]]
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:873)
... 24 more
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[]]
at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:419)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:186)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1332)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1322)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866)
... 24 more
Caused by: java.lang.IllegalArgumentException: URI scheme is not "file"
at java.base/java.io.File.<init>(File.java:423)
at org.apache.catalina.webresources.StandardRoot$BaseLocation.<init>(StandardRoot.java:826)
at org.apache.catalina.webresources.StandardRoot.createWebResourceSet(StandardRoot.java:358)
at org.apache.catalina.startup.ContextConfig.processResourceJARs(ContextConfig.java:1903)
at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1358)
at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:991)
at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:304)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:114)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4782)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171)
... 30 more
As the Spring boot 3.2.1 release notes: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.2-Release-Notes
The URL format of jar:file:/dir/myjar.jar:BOOT-INF/lib/nested.jar!/com/example/MyClass.class
has been replaced with jar:nested:/dir/myjar.jar/!BOOT-INF/lib/nested.jar!/com/example/MyClass.class
, but embedded Tomcat cannot recognize the URL format "jar:nested", so it reported error URI scheme is not "file"
.
Is there any solution to fix this issue? Or we have to fallback to the CLASSIC boot loader?
Comment From: wilkinsona
It's hard to say without knowing more about the problem. Judging by the stack trace, you have some custom code that's bootstrapping Tomcat rather than using Spring Boot's TomcatWebServer
. This means that you are missing the static resource configuration that's performed by TomcatServletWebServerFactory
through StaticResourceConfigurer
and NestedJarResourceSet
. I think you'll either need to replicate this logic in your custom Tomcat bootstrapping code or you'll have to drop back to the classic loader.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Comment From: dicer
I also run into this error after upgrading from spring boot 2.7.18 to 3.3.0. We are running as a WAR file (standalone, not in an appserver) and deploy an additional WAR file into the spring boot tomcat. The error happens because the additional WAR finds/needs classes of the spring boot WAR (parent class loader is set), but can not access those.
The following code works fine in spring boot 2, but does not work anymore in 3. Any suggestions? Can I supply more info?
@Bean
public TomcatServletWebServerFactory servletContainerFactory(@Value("${addon.war.file}") String path,
@Value("${addon.war.context:}") String contextPath) {
return new TomcatServletWebServerFactory() {
@Override
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
File webappsDir = new File(tomcat.getServer().getCatalinaBase(), "webapps");
try {
FileUtils.forceMkdir(webappsDir);
} catch (IOException e) {
throw new RuntimeException("Could not create webapps directory", e);
}
File extractedWar;
try (InputStream resourceAsStream = this.getClass().getResourceAsStream(path)) {
extractedWar = File.createTempFile("addon", ".war");
if (resourceAsStream == null) {
logger.error("Could not find specified addon.war at '" + path + "'. Could not deploy addon");
return super.getTomcatWebServer(tomcat);
}
FileUtils.copyInputStreamToFile(resourceAsStream, extractedWar);
Context context = tomcat.addWebapp(contextPath, extractedWar.getAbsolutePath());
context.setParentClassLoader(getClass().getClassLoader());
logger.debug("Deployed addon into internal tomcat");
} catch (IOException e) {
logger.error("Error deploying addon war into internal tomcat", e);
}
return super.getTomcatWebServer(tomcat);
}
};
}
Comment From: philwebb
@dicer It's hard to say what the problem might be. Please could you post the question on stackoverflow.com along with a sample that reproduces the problem. If you provide a link to the question here we can try to take a look.
Comment From: hskprzemek
@dicer Hi, I stuck on the same issue when upgrading from spring boot 2 to 3. Did you find a solution ?