mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Separate stopping and destruction so web server can be restarted
Previously, when a Servlet-based WebServer was stopped it would also stop the ServletContext. This led to problems as Tomcat and Undertow would then not allow a restart. Jetty would allow a restart but duplicate servlet registrations would then be attempted. This commit modifies the WebServer lifecycle to separate stopping and destruction for both servlet and reactive web servers. This allows a WebServer's stop() implementation to leave some components running so that they can be restarted. To completely shut down a WebServer destroy() must now be called. Both Tomcat and Jetty WebServers have been updated to stop their network connections when stop() is called but leave other components running. This works with both servlet and reactive web servers. Note that an Undertow-based Servlet web server does not support stop and restart. Once stopped, a Servlet Deployment cannot be restarted and it does not appear to be possible to separate the lifecycle of its network connections and a Servlet deployment. Reactor Netty and Undertow-based reactive web servers can now also be stopped and then restarted. Calling stop() stops the whole server but this does not cause a problem as there's no (application-exposed) ServletContext involved. There may be room to optimize this in the future if the need arises. Closes gh-34955
This commit is contained in:
parent
47cc65d912
commit
dbb24286ff
@ -238,7 +238,9 @@ public class JettyWebServer implements WebServer {
|
|||||||
this.gracefulShutdown.abort();
|
this.gracefulShutdown.abort();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.server.stop();
|
for (Connector connector : this.server.getConnectors()) {
|
||||||
|
connector.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (InterruptedException ex) {
|
catch (InterruptedException ex) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
@ -249,6 +251,18 @@ public class JettyWebServer implements WebServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
synchronized (this.monitor) {
|
||||||
|
try {
|
||||||
|
this.server.stop();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new WebServerException("Unable to destroy embedded Jetty server", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
Connector[] connectors = this.server.getConnectors();
|
Connector[] connectors = this.server.getConnectors();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2020 the original author or authors.
|
* Copyright 2012-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -60,14 +60,14 @@ final class GracefulShutdown {
|
|||||||
try {
|
try {
|
||||||
for (Container host : this.tomcat.getEngine().findChildren()) {
|
for (Container host : this.tomcat.getEngine().findChildren()) {
|
||||||
for (Container context : host.findChildren()) {
|
for (Container context : host.findChildren()) {
|
||||||
while (isActive(context)) {
|
while (!this.aborted && isActive(context)) {
|
||||||
|
Thread.sleep(50);
|
||||||
|
}
|
||||||
if (this.aborted) {
|
if (this.aborted) {
|
||||||
logger.info("Graceful shutdown aborted with one or more requests still active");
|
logger.info("Graceful shutdown aborted with one or more requests still active");
|
||||||
callback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE);
|
callback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Thread.sleep(50);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +209,7 @@ public class TomcatWebServer implements WebServer {
|
|||||||
if (this.started) {
|
if (this.started) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
addPreviouslyRemovedConnectors();
|
addPreviouslyRemovedConnectors();
|
||||||
Connector connector = this.tomcat.getConnector();
|
Connector connector = this.tomcat.getConnector();
|
||||||
@ -324,16 +325,10 @@ public class TomcatWebServer implements WebServer {
|
|||||||
boolean wasStarted = this.started;
|
boolean wasStarted = this.started;
|
||||||
try {
|
try {
|
||||||
this.started = false;
|
this.started = false;
|
||||||
try {
|
|
||||||
if (this.gracefulShutdown != null) {
|
if (this.gracefulShutdown != null) {
|
||||||
this.gracefulShutdown.abort();
|
this.gracefulShutdown.abort();
|
||||||
}
|
}
|
||||||
stopTomcat();
|
removeServiceConnectors();
|
||||||
this.tomcat.destroy();
|
|
||||||
}
|
|
||||||
catch (LifecycleException ex) {
|
|
||||||
// swallow and continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new WebServerException("Unable to stop embedded Tomcat", ex);
|
throw new WebServerException("Unable to stop embedded Tomcat", ex);
|
||||||
@ -346,6 +341,19 @@ public class TomcatWebServer implements WebServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void destroy() throws WebServerException {
|
||||||
|
try {
|
||||||
|
stopTomcat();
|
||||||
|
this.tomcat.destroy();
|
||||||
|
}
|
||||||
|
catch (LifecycleException ex) {
|
||||||
|
// Swallow and continue
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new WebServerException("Unable to destroy embedded Tomcat", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String getPortsDescription(boolean localPort) {
|
private String getPortsDescription(boolean localPort) {
|
||||||
StringBuilder ports = new StringBuilder();
|
StringBuilder ports = new StringBuilder();
|
||||||
for (Connector connector : this.tomcat.getService().findConnectors()) {
|
for (Connector connector : this.tomcat.getService().findConnectors()) {
|
||||||
|
@ -132,13 +132,13 @@ public class UndertowWebServer implements WebServer {
|
|||||||
throw new WebServerException("Unable to start embedded Undertow", ex);
|
throw new WebServerException("Unable to start embedded Undertow", ex);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
stopSilently();
|
destroySilently();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopSilently() {
|
private void destroySilently() {
|
||||||
try {
|
try {
|
||||||
if (this.undertow != null) {
|
if (this.undertow != null) {
|
||||||
this.undertow.stop();
|
this.undertow.stop();
|
||||||
@ -274,7 +274,7 @@ public class UndertowWebServer implements WebServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new WebServerException("Unable to stop undertow", ex);
|
throw new WebServerException("Unable to stop Undertow", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2020 the original author or authors.
|
* Copyright 2012-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -61,4 +61,12 @@ public interface WebServer {
|
|||||||
callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE);
|
callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the web server such that it cannot be started again.
|
||||||
|
* @since 3.2.0
|
||||||
|
*/
|
||||||
|
default void destroy() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2022 the original author or authors.
|
* Copyright 2012-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -149,6 +149,7 @@ public class ServletWebServerApplicationContext extends GenericWebApplicationCon
|
|||||||
WebServer webServer = this.webServer;
|
WebServer webServer = this.webServer;
|
||||||
if (webServer != null) {
|
if (webServer != null) {
|
||||||
webServer.stop();
|
webServer.stop();
|
||||||
|
webServer.destroy();
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
@ -171,6 +172,10 @@ public class ServletWebServerApplicationContext extends GenericWebApplicationCon
|
|||||||
AvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC);
|
AvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC);
|
||||||
}
|
}
|
||||||
super.doClose();
|
super.doClose();
|
||||||
|
WebServer webServer = this.webServer;
|
||||||
|
if (webServer != null) {
|
||||||
|
webServer.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createWebServer() {
|
private void createWebServer() {
|
||||||
|
@ -234,10 +234,10 @@ class JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryT
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void stopCalledWithoutStart() {
|
void destroyCalledWithoutStart() {
|
||||||
JettyServletWebServerFactory factory = getFactory();
|
JettyServletWebServerFactory factory = getFactory();
|
||||||
this.webServer = factory.getWebServer(exampleServletRegistration());
|
this.webServer = factory.getWebServer(exampleServletRegistration());
|
||||||
this.webServer.stop();
|
this.webServer.destroy();
|
||||||
Server server = ((JettyWebServer) this.webServer).getServer();
|
Server server = ((JettyWebServer) this.webServer).getServer();
|
||||||
assertThat(server.isStopped()).isTrue();
|
assertThat(server.isStopped()).isTrue();
|
||||||
}
|
}
|
||||||
|
@ -340,10 +340,10 @@ class TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void stopCalledWithoutStart() {
|
void destroyCalledWithoutStart() {
|
||||||
TomcatServletWebServerFactory factory = getFactory();
|
TomcatServletWebServerFactory factory = getFactory();
|
||||||
this.webServer = factory.getWebServer(exampleServletRegistration());
|
this.webServer = factory.getWebServer(exampleServletRegistration());
|
||||||
this.webServer.stop();
|
this.webServer.destroy();
|
||||||
Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();
|
Tomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();
|
||||||
assertThat(tomcat.getServer().getState()).isSameAs(LifecycleState.DESTROYED);
|
assertThat(tomcat.getServer().getState()).isSameAs(LifecycleState.DESTROYED);
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ import org.apache.hc.core5.http.HttpResponse;
|
|||||||
import org.apache.jasper.servlet.JspServlet;
|
import org.apache.jasper.servlet.JspServlet;
|
||||||
import org.awaitility.Awaitility;
|
import org.awaitility.Awaitility;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
|
|
||||||
@ -211,6 +212,20 @@ class UndertowServletWebServerFactoryTests extends AbstractServletWebServerFacto
|
|||||||
this.webServer.stop();
|
this.webServer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Override
|
||||||
|
@Disabled("Restart after stop is not supported with Undertow")
|
||||||
|
protected void restartAfterStop() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Override
|
||||||
|
@Disabled("Undertow's architecture prevents separating stop and destroy")
|
||||||
|
protected void servletContextListenerContextDestroyedIsNotCalledWhenContainerIsStopped() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void testAccessLog(String prefix, String suffix, String expectedFile)
|
private void testAccessLog(String prefix, String suffix, String expectedFile)
|
||||||
throws IOException, URISyntaxException {
|
throws IOException, URISyntaxException {
|
||||||
UndertowServletWebServerFactory factory = getFactory();
|
UndertowServletWebServerFactory factory = getFactory();
|
||||||
|
@ -77,6 +77,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||||||
import org.springframework.web.reactive.function.client.WebClientRequestException;
|
import org.springframework.web.reactive.function.client.WebClientRequestException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatException;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
@ -95,6 +96,12 @@ public abstract class AbstractReactiveWebServerFactoryTests {
|
|||||||
if (this.webServer != null) {
|
if (this.webServer != null) {
|
||||||
try {
|
try {
|
||||||
this.webServer.stop();
|
this.webServer.stop();
|
||||||
|
try {
|
||||||
|
this.webServer.destroy();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
// Ignore
|
// Ignore
|
||||||
@ -124,13 +131,37 @@ public abstract class AbstractReactiveWebServerFactoryTests {
|
|||||||
assertThat(this.webServer.getPort()).isEqualTo(specificPort);
|
assertThat(this.webServer.getPort()).isEqualTo(specificPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
protected void restartAfterStop() throws Exception {
|
||||||
|
AbstractReactiveWebServerFactory factory = getFactory();
|
||||||
|
this.webServer = factory.getWebServer(new EchoHandler());
|
||||||
|
this.webServer.start();
|
||||||
|
int port = this.webServer.getPort();
|
||||||
|
assertThat(getResponse(port, "/test")).isEqualTo("Hello World");
|
||||||
|
this.webServer.stop();
|
||||||
|
assertThatException().isThrownBy(() -> getResponse(port, "/test"));
|
||||||
|
this.webServer.start();
|
||||||
|
assertThat(getResponse(this.webServer.getPort(), "/test")).isEqualTo("Hello World");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getResponse(int port, String uri) {
|
||||||
|
WebClient webClient = getWebClient(port).build();
|
||||||
|
Mono<String> result = webClient.post()
|
||||||
|
.uri(uri)
|
||||||
|
.contentType(MediaType.TEXT_PLAIN)
|
||||||
|
.body(BodyInserters.fromValue("Hello World"))
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
return result.block(Duration.ofSeconds(30));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void portIsMinusOneWhenConnectionIsClosed() {
|
void portIsMinusOneWhenConnectionIsClosed() {
|
||||||
AbstractReactiveWebServerFactory factory = getFactory();
|
AbstractReactiveWebServerFactory factory = getFactory();
|
||||||
this.webServer = factory.getWebServer(new EchoHandler());
|
this.webServer = factory.getWebServer(new EchoHandler());
|
||||||
this.webServer.start();
|
this.webServer.start();
|
||||||
assertThat(this.webServer.getPort()).isGreaterThan(0);
|
assertThat(this.webServer.getPort()).isGreaterThan(0);
|
||||||
this.webServer.stop();
|
this.webServer.destroy();
|
||||||
assertThat(this.webServer.getPort()).isEqualTo(-1);
|
assertThat(this.webServer.getPort()).isEqualTo(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +84,7 @@ import static org.mockito.BDDMockito.then;
|
|||||||
import static org.mockito.Mockito.atMost;
|
import static org.mockito.Mockito.atMost;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.withSettings;
|
import static org.mockito.Mockito.withSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,12 +157,35 @@ class ServletWebServerApplicationContextTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void stopOnClose() {
|
void stopOnStop() {
|
||||||
|
addWebServerFactoryBean();
|
||||||
|
this.context.refresh();
|
||||||
|
MockServletWebServerFactory factory = getWebServerFactory();
|
||||||
|
then(factory.getWebServer()).should().start();
|
||||||
|
this.context.stop();
|
||||||
|
then(factory.getWebServer()).should().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void startOnStartAfterStop() {
|
||||||
|
addWebServerFactoryBean();
|
||||||
|
this.context.refresh();
|
||||||
|
MockServletWebServerFactory factory = getWebServerFactory();
|
||||||
|
then(factory.getWebServer()).should().start();
|
||||||
|
this.context.stop();
|
||||||
|
then(factory.getWebServer()).should().stop();
|
||||||
|
this.context.start();
|
||||||
|
then(factory.getWebServer()).should(times(2)).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void stopAndDestroyOnClose() {
|
||||||
addWebServerFactoryBean();
|
addWebServerFactoryBean();
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
MockServletWebServerFactory factory = getWebServerFactory();
|
MockServletWebServerFactory factory = getWebServerFactory();
|
||||||
this.context.close();
|
this.context.close();
|
||||||
then(factory.getWebServer()).should().stop();
|
then(factory.getWebServer()).should(times(2)).stop();
|
||||||
|
then(factory.getWebServer()).should().destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -167,6 +167,7 @@ import static org.mockito.BDDMockito.then;
|
|||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base for testing classes that extends {@link AbstractServletWebServerFactory}.
|
* Base for testing classes that extends {@link AbstractServletWebServerFactory}.
|
||||||
@ -197,6 +198,12 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||||||
if (this.webServer != null) {
|
if (this.webServer != null) {
|
||||||
try {
|
try {
|
||||||
this.webServer.stop();
|
this.webServer.stop();
|
||||||
|
try {
|
||||||
|
this.webServer.destroy();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
// Ignore
|
// Ignore
|
||||||
@ -233,6 +240,19 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||||||
this.webServer.stop();
|
this.webServer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
protected void restartAfterStop() throws IOException, URISyntaxException {
|
||||||
|
AbstractServletWebServerFactory factory = getFactory();
|
||||||
|
this.webServer = factory.getWebServer(exampleServletRegistration());
|
||||||
|
this.webServer.start();
|
||||||
|
assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World");
|
||||||
|
int port = this.webServer.getPort();
|
||||||
|
this.webServer.stop();
|
||||||
|
assertThatIOException().isThrownBy(() -> getResponse(getLocalUrl(port, "/hello")));
|
||||||
|
this.webServer.start();
|
||||||
|
assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void emptyServerWhenPortIsMinusOne() {
|
void emptyServerWhenPortIsMinusOne() {
|
||||||
AbstractServletWebServerFactory factory = getFactory();
|
AbstractServletWebServerFactory factory = getFactory();
|
||||||
@ -295,7 +315,7 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||||||
this.webServer = factory.getWebServer();
|
this.webServer = factory.getWebServer();
|
||||||
this.webServer.start();
|
this.webServer.start();
|
||||||
assertThat(this.webServer.getPort()).isGreaterThan(0);
|
assertThat(this.webServer.getPort()).isGreaterThan(0);
|
||||||
this.webServer.stop();
|
this.webServer.destroy();
|
||||||
assertThat(this.webServer.getPort()).isEqualTo(-1);
|
assertThat(this.webServer.getPort()).isEqualTo(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,7 +834,7 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||||||
this.webServer.start();
|
this.webServer.start();
|
||||||
String s1 = getResponse(getLocalUrl("/session"));
|
String s1 = getResponse(getLocalUrl("/session"));
|
||||||
String s2 = getResponse(getLocalUrl("/session"));
|
String s2 = getResponse(getLocalUrl("/session"));
|
||||||
this.webServer.stop();
|
this.webServer.destroy();
|
||||||
this.webServer = factory.getWebServer(sessionServletRegistration());
|
this.webServer = factory.getWebServer(sessionServletRegistration());
|
||||||
this.webServer.start();
|
this.webServer.start();
|
||||||
String s3 = getResponse(getLocalUrl("/session"));
|
String s3 = getResponse(getLocalUrl("/session"));
|
||||||
@ -833,7 +853,7 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||||||
this.webServer = factory.getWebServer(sessionServletRegistration());
|
this.webServer = factory.getWebServer(sessionServletRegistration());
|
||||||
this.webServer.start();
|
this.webServer.start();
|
||||||
getResponse(getLocalUrl("/session"));
|
getResponse(getLocalUrl("/session"));
|
||||||
this.webServer.stop();
|
this.webServer.destroy();
|
||||||
File[] dirContents = sessionStoreDir.listFiles((dir, name) -> !(".".equals(name) || "..".equals(name)));
|
File[] dirContents = sessionStoreDir.listFiles((dir, name) -> !(".".equals(name) || "..".equals(name)));
|
||||||
assertThat(dirContents).isNotEmpty();
|
assertThat(dirContents).isNotEmpty();
|
||||||
}
|
}
|
||||||
@ -1158,11 +1178,20 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void servletContextListenerContextDestroyedIsCalledWhenContainerIsStopped() throws Exception {
|
protected void servletContextListenerContextDestroyedIsNotCalledWhenContainerIsStopped() throws Exception {
|
||||||
ServletContextListener listener = mock(ServletContextListener.class);
|
ServletContextListener listener = mock(ServletContextListener.class);
|
||||||
this.webServer = getFactory().getWebServer((servletContext) -> servletContext.addListener(listener));
|
this.webServer = getFactory().getWebServer((servletContext) -> servletContext.addListener(listener));
|
||||||
this.webServer.start();
|
this.webServer.start();
|
||||||
this.webServer.stop();
|
this.webServer.stop();
|
||||||
|
then(listener).should(times(0)).contextDestroyed(any(ServletContextEvent.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void servletContextListenerContextDestroyedIsCalledWhenContainerIsDestroyed() throws Exception {
|
||||||
|
ServletContextListener listener = mock(ServletContextListener.class);
|
||||||
|
this.webServer = getFactory().getWebServer((servletContext) -> servletContext.addListener(listener));
|
||||||
|
this.webServer.start();
|
||||||
|
this.webServer.destroy();
|
||||||
then(listener).should().contextDestroyed(any(ServletContextEvent.class));
|
then(listener).should().contextDestroyed(any(ServletContextEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2021 the original author or authors.
|
* Copyright 2012-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -53,7 +53,7 @@ public class LoaderTestApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(LoaderTestApplication.class, args).stop();
|
SpringApplication.run(LoaderTestApplication.class, args).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user