From cc3aea2b69cbcc3b46d279a47c9a52107242c7c8 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 29 Jun 2015 16:52:05 +0100 Subject: [PATCH] =?UTF-8?q?Prevent=20Jetty=E2=80=99s=20singleton=20shutdow?= =?UTF-8?q?n=20thread=20from=20breaking=20restarts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default, Jetty uses a singleton shutdown thread, registered as a shutdown hook, to stop its components. This single thread breaks the restart logic in devtools as a second restart causes a second attempt to start the singleton shutdown thread which fails with an IllegalStateException. This processing is unnecessary in a Spring Boot application as the application context’s lifecycle when ensure that Jetty is shutdown. This commit updates the embedded Jetty container to remove its components from Jetty’s shutdown thread. This leaves the thread with no components to manage at which point it removes its registration as a shutdown hook. Closes gh-3343 --- .../websocket/JettyWebSocketContainerCustomizer.java | 6 +++++- .../embedded/jetty/JettyEmbeddedServletContainer.java | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/JettyWebSocketContainerCustomizer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/JettyWebSocketContainerCustomizer.java index 64c0224115..c510f311df 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/JettyWebSocketContainerCustomizer.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/websocket/JettyWebSocketContainerCustomizer.java @@ -16,8 +16,10 @@ package org.springframework.boot.autoconfigure.websocket; +import org.eclipse.jetty.util.thread.ShutdownThread; import org.eclipse.jetty.webapp.AbstractConfiguration; import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory; @@ -38,7 +40,9 @@ public class JettyWebSocketContainerCustomizer extends @Override public void configure(WebAppContext context) throws Exception { - WebSocketServerContainerInitializer.configureContext(context); + ServerContainer serverContainer = WebSocketServerContainerInitializer + .configureContext(context); + ShutdownThread.deregister(serverContainer); } }); diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainer.java index e896dfe4c0..1e8616e9ed 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainer.java @@ -81,6 +81,7 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer { // Start the server so that the ServletContext is available this.server.start(); + this.server.setStopAtShutdown(false); } catch (Exception ex) { // Ensure process isn't left running