Ensure embedded start can be called multiple times

Update all `EmbeddedServletContainer` implementations to ensure that
the `start()` method can be called multiple times, with the second call
being ignored.

Fixes gh-8036
pull/8196/head
Phillip Webb 8 years ago
parent ef69ae6a89
commit 0af53b361f

@ -59,6 +59,8 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
private Connector[] connectors; private Connector[] connectors;
private volatile boolean started;
/** /**
* Create a new {@link JettyEmbeddedServletContainer} instance. * Create a new {@link JettyEmbeddedServletContainer} instance.
* @param server the underlying Jetty server * @param server the underlying Jetty server
@ -111,6 +113,10 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
@Override @Override
public void start() throws EmbeddedServletContainerException { public void start() throws EmbeddedServletContainerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
this.server.setConnectors(this.connectors); this.server.setConnectors(this.connectors);
if (!this.autoStart) { if (!this.autoStart) {
return; return;
@ -133,6 +139,7 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
throw ex; throw ex;
} }
} }
this.started = true;
JettyEmbeddedServletContainer.logger JettyEmbeddedServletContainer.logger
.info("Jetty started on port(s) " + getActualPortsDescription()); .info("Jetty started on port(s) " + getActualPortsDescription());
} }
@ -144,6 +151,7 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
"Unable to start embedded Jetty servlet container", ex); "Unable to start embedded Jetty servlet container", ex);
} }
} }
}
private String getActualPortsDescription() { private String getActualPortsDescription() {
StringBuilder ports = new StringBuilder(); StringBuilder ports = new StringBuilder();
@ -197,6 +205,10 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer {
@Override @Override
public void stop() { public void stop() {
synchronized (this.monitor) { synchronized (this.monitor) {
if (!this.started) {
return;
}
this.started = false;
try { try {
this.server.stop(); this.server.stop();
} }

@ -62,6 +62,8 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
private final boolean autoStart; private final boolean autoStart;
private volatile boolean started;
/** /**
* Create a new {@link TomcatEmbeddedServletContainer} instance. * Create a new {@link TomcatEmbeddedServletContainer} instance.
* @param tomcat the underlying Tomcat server * @param tomcat the underlying Tomcat server
@ -174,6 +176,10 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
@Override @Override
public void start() throws EmbeddedServletContainerException { public void start() throws EmbeddedServletContainerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
try { try {
addPreviouslyRemovedConnectors(); addPreviouslyRemovedConnectors();
Connector connector = this.tomcat.getConnector(); Connector connector = this.tomcat.getConnector();
@ -181,6 +187,7 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
startConnector(connector); startConnector(connector);
} }
checkThatConnectorsHaveStarted(); checkThatConnectorsHaveStarted();
this.started = true;
TomcatEmbeddedServletContainer.logger TomcatEmbeddedServletContainer.logger
.info("Tomcat started on port(s): " + getPortsDescription(true)); .info("Tomcat started on port(s): " + getPortsDescription(true));
} }
@ -198,6 +205,7 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
getClass().getClassLoader()); getClass().getClassLoader());
} }
} }
}
private void checkThatConnectorsHaveStarted() { private void checkThatConnectorsHaveStarted() {
for (Connector connector : this.tomcat.getService().findConnectors()) { for (Connector connector : this.tomcat.getService().findConnectors()) {
@ -271,7 +279,11 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
@Override @Override
public void stop() throws EmbeddedServletContainerException { public void stop() throws EmbeddedServletContainerException {
synchronized (this.monitor) { synchronized (this.monitor) {
if (!this.started) {
return;
}
try { try {
this.started = false;
try { try {
stopTomcat(); stopTomcat();
this.tomcat.destroy(); this.tomcat.destroy();

@ -88,7 +88,7 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
private Undertow undertow; private Undertow undertow;
private boolean started = false; private volatile boolean started = false;
/** /**
* Create a new {@link UndertowEmbeddedServletContainer} instance. * Create a new {@link UndertowEmbeddedServletContainer} instance.
@ -201,6 +201,9 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
@Override @Override
public void start() throws EmbeddedServletContainerException { public void start() throws EmbeddedServletContainerException {
synchronized (this.monitor) { synchronized (this.monitor) {
if (this.started) {
return;
}
try { try {
if (!this.autoStart) { if (!this.autoStart) {
return; return;
@ -362,9 +365,11 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
@Override @Override
public void stop() throws EmbeddedServletContainerException { public void stop() throws EmbeddedServletContainerException {
synchronized (this.monitor) { synchronized (this.monitor) {
if (this.started) { if (!this.started) {
try { return;
}
this.started = false; this.started = false;
try {
this.manager.stop(); this.manager.stop();
this.undertow.stop(); this.undertow.stop();
} }
@ -374,7 +379,6 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
} }
} }
} }
}
@Override @Override
public int getPort() { public int getPort() {

@ -79,6 +79,7 @@ import org.mockito.InOrder;
import org.springframework.boot.ApplicationHome; import org.springframework.boot.ApplicationHome;
import org.springframework.boot.ApplicationTemp; import org.springframework.boot.ApplicationTemp;
import org.springframework.boot.context.embedded.Ssl.ClientAuth; import org.springframework.boot.context.embedded.Ssl.ClientAuth;
import org.springframework.boot.testutil.InternalOutputCapture;
import org.springframework.boot.web.servlet.ErrorPage; import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletContextInitializer;
@ -120,6 +121,9 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
@Rule @Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder(); public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Rule
public InternalOutputCapture output = new InternalOutputCapture();
protected EmbeddedServletContainer container; protected EmbeddedServletContainer container;
private final HttpClientContext httpClientContext = HttpClientContext.create(); private final HttpClientContext httpClientContext = HttpClientContext.create();
@ -153,6 +157,19 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World"); assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World");
} }
@Test
public void startCalledTwice() throws Exception {
AbstractEmbeddedServletContainerFactory factory = getFactory();
this.container = factory
.getEmbeddedServletContainer(exampleServletRegistration());
this.container.start();
int port = this.container.getPort();
this.container.start();
assertThat(this.container.getPort()).isEqualTo(port);
assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World");
assertThat(this.output.toString()).containsOnlyOnce("started on port");
}
@Test @Test
public void emptyServerWhenPortIsMinusOne() throws Exception { public void emptyServerWhenPortIsMinusOne() throws Exception {
AbstractEmbeddedServletContainerFactory factory = getFactory(); AbstractEmbeddedServletContainerFactory factory = getFactory();

Loading…
Cancel
Save