Skip to content

Commit 2bb7a43

Browse files
philwebbwilkinsona
authored andcommitted
Clean up access logging threads when Undertow is stopped
Closes gh-12742
1 parent e7b03f7 commit 2bb7a43

File tree

2 files changed

+63
-17
lines changed

2 files changed

+63
-17
lines changed

spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.Arrays;
3333
import java.util.Collection;
3434
import java.util.Collections;
35+
import java.util.EventListener;
3536
import java.util.List;
3637
import java.util.Locale;
3738
import java.util.Map;
@@ -46,6 +47,8 @@
4647
import javax.net.ssl.X509ExtendedKeyManager;
4748
import javax.servlet.ServletContainerInitializer;
4849
import javax.servlet.ServletContext;
50+
import javax.servlet.ServletContextEvent;
51+
import javax.servlet.ServletContextListener;
4952
import javax.servlet.ServletException;
5053

5154
import io.undertow.Undertow;
@@ -64,6 +67,7 @@
6467
import io.undertow.servlet.Servlets;
6568
import io.undertow.servlet.api.DeploymentInfo;
6669
import io.undertow.servlet.api.DeploymentManager;
70+
import io.undertow.servlet.api.ListenerInfo;
6771
import io.undertow.servlet.api.MimeMapping;
6872
import io.undertow.servlet.api.ServletContainerInitializerInfo;
6973
import io.undertow.servlet.api.ServletStackTraces;
@@ -417,34 +421,41 @@ private DeploymentManager createDeploymentManager(
417421
}
418422

419423
private void configureAccessLog(DeploymentInfo deploymentInfo) {
420-
deploymentInfo.addInitialHandlerChainWrapper(new HandlerWrapper() {
421-
422-
@Override
423-
public HttpHandler wrap(HttpHandler handler) {
424-
return createAccessLogHandler(handler);
425-
}
426-
427-
});
428-
}
429-
430-
private AccessLogHandler createAccessLogHandler(HttpHandler handler) {
431424
try {
432425
createAccessLogDirectoryIfNecessary();
426+
XnioWorker worker = createWorker();
433427
String prefix = (this.accessLogPrefix != null ? this.accessLogPrefix
434428
: "access_log.");
435-
AccessLogReceiver accessLogReceiver = new DefaultAccessLogReceiver(
436-
createWorker(), this.accessLogDirectory, prefix, this.accessLogSuffix,
429+
DefaultAccessLogReceiver accessLogReceiver = new DefaultAccessLogReceiver(
430+
worker, this.accessLogDirectory, prefix, this.accessLogSuffix,
437431
this.accessLogRotate);
438-
String formatString = (this.accessLogPattern != null ? this.accessLogPattern
439-
: "common");
440-
return new AccessLogHandler(handler, accessLogReceiver, formatString,
441-
Undertow.class.getClassLoader());
432+
EventListener listener = new AccessLogShutdownListener(worker,
433+
accessLogReceiver);
434+
deploymentInfo.addListener(new ListenerInfo(AccessLogShutdownListener.class,
435+
new ImmediateInstanceFactory<EventListener>(listener)));
436+
deploymentInfo.addInitialHandlerChainWrapper(new HandlerWrapper() {
437+
438+
@Override
439+
public HttpHandler wrap(HttpHandler handler) {
440+
return createAccessLogHandler(handler, accessLogReceiver);
441+
}
442+
443+
});
442444
}
443445
catch (IOException ex) {
444446
throw new IllegalStateException("Failed to create AccessLogHandler", ex);
445447
}
446448
}
447449

450+
private AccessLogHandler createAccessLogHandler(HttpHandler handler,
451+
AccessLogReceiver accessLogReceiver) {
452+
createAccessLogDirectoryIfNecessary();
453+
String formatString = (this.accessLogPattern != null) ? this.accessLogPattern
454+
: "common";
455+
return new AccessLogHandler(handler, accessLogReceiver, formatString,
456+
Undertow.class.getClassLoader());
457+
}
458+
448459
private void createAccessLogDirectoryIfNecessary() {
449460
Assert.state(this.accessLogDirectory != null, "Access log directory is not set");
450461
if (!this.accessLogDirectory.isDirectory() && !this.accessLogDirectory.mkdirs()) {
@@ -790,4 +801,33 @@ public String[] getServerAliases(String keyType, Principal[] issuers) {
790801

791802
}
792803

804+
private static class AccessLogShutdownListener implements ServletContextListener {
805+
806+
private final XnioWorker worker;
807+
808+
private final DefaultAccessLogReceiver accessLogReceiver;
809+
810+
AccessLogShutdownListener(XnioWorker worker,
811+
DefaultAccessLogReceiver accessLogReceiver) {
812+
this.worker = worker;
813+
this.accessLogReceiver = accessLogReceiver;
814+
}
815+
816+
@Override
817+
public void contextInitialized(ServletContextEvent sce) {
818+
}
819+
820+
@Override
821+
public void contextDestroyed(ServletContextEvent sce) {
822+
try {
823+
this.accessLogReceiver.close();
824+
this.worker.shutdown();
825+
}
826+
catch (IOException ex) {
827+
throw new IllegalStateException(ex);
828+
}
829+
}
830+
831+
}
832+
793833
}

spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import io.undertow.servlet.api.DeploymentManager;
3838
import io.undertow.servlet.api.ServletContainer;
3939
import org.apache.jasper.servlet.JspServlet;
40+
import org.junit.AfterClass;
4041
import org.junit.Test;
4142
import org.mockito.InOrder;
4243

@@ -73,6 +74,11 @@ protected UndertowEmbeddedServletContainerFactory getFactory() {
7374
return new UndertowEmbeddedServletContainerFactory(0);
7475
}
7576

77+
@AfterClass
78+
public static void afterClass() {
79+
80+
}
81+
7682
@Test
7783
public void errorPage404() throws Exception {
7884
AbstractEmbeddedServletContainerFactory factory = getFactory();

0 commit comments

Comments
 (0)