Skip to content

Commit 8651e97

Browse files
committed
Replace TomcatStarter to break servlet dependency
Replace `TomcatStarter` with a `DeferredStartupExceptions` interface to break the direct dependency on `Servlet`. Closes gh-44325
1 parent 111418f commit 8651e97

File tree

4 files changed

+47
-23
lines changed

4 files changed

+47
-23
lines changed

module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatEmbeddedContext.java

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
import org.springframework.boot.web.server.MimeMappings;
3636
import org.springframework.boot.web.server.WebServerException;
37+
import org.springframework.util.Assert;
3738
import org.springframework.util.ClassUtils;
3839

3940
/**
@@ -46,7 +47,7 @@
4647
*/
4748
public class TomcatEmbeddedContext extends StandardContext {
4849

49-
private @Nullable TomcatStarter starter;
50+
private DeferredStartupExceptions deferredStartupExceptions = DeferredStartupExceptions.NONE;
5051

5152
private @Nullable MimeMappings mimeMappings;
5253

@@ -116,12 +117,17 @@ private void doWithThreadContextClassLoader(@Nullable ClassLoader classLoader, R
116117
}
117118
}
118119

119-
public void setStarter(@Nullable TomcatStarter starter) {
120-
this.starter = starter;
120+
/**
121+
* Set the a strategy used to capture and rethrow deferred startup exceptions.
122+
* @param deferredStartupExceptions the strategy to use
123+
*/
124+
public void setDeferredStartupExceptions(DeferredStartupExceptions deferredStartupExceptions) {
125+
Assert.notNull(deferredStartupExceptions, "'deferredStartupExceptions' must not be null");
126+
this.deferredStartupExceptions = deferredStartupExceptions;
121127
}
122128

123-
@Nullable TomcatStarter getStarter() {
124-
return this.starter;
129+
DeferredStartupExceptions getDeferredStartupExceptions() {
130+
return this.deferredStartupExceptions;
125131
}
126132

127133
public void setMimeMappings(MimeMappings mimeMappings) {
@@ -146,4 +152,24 @@ public String[] findMimeMappings() {
146152
return (this.mimeMappings != null) ? this.mimeMappings.get(extension) : null;
147153
}
148154

155+
/**
156+
* Strategy interface that can be used to rethrow deferred startup exceptions.
157+
*/
158+
@FunctionalInterface
159+
public interface DeferredStartupExceptions {
160+
161+
/**
162+
* {@link DeferredStartupExceptions} that does nothing.
163+
*/
164+
DeferredStartupExceptions NONE = () -> {
165+
};
166+
167+
/**
168+
* Rethrow deferred startup exceptions if there are any.
169+
* @throws Exception the deferred startup exception
170+
*/
171+
void rethrow() throws Exception;
172+
173+
}
174+
149175
}

module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatWebServer.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,7 @@ private void rethrowDeferredStartupExceptions() throws Exception {
200200
Container[] children = this.tomcat.getHost().findChildren();
201201
for (Container container : children) {
202202
if (container instanceof TomcatEmbeddedContext embeddedContext) {
203-
TomcatStarter tomcatStarter = embeddedContext.getStarter();
204-
if (tomcatStarter != null) {
205-
Exception exception = tomcatStarter.getStartUpException();
206-
if (exception != null) {
207-
throw exception;
208-
}
209-
}
203+
embeddedContext.getDeferredStartupExceptions().rethrow();
210204
}
211205
if (!LifecycleState.STARTED.equals(container.getState())) {
212206
throw new IllegalStateException(container + " failed to start");

module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatStarter.java renamed to module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/servlet/DeferredServletContainerInitializers.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.tomcat;
17+
package org.springframework.boot.tomcat.servlet;
1818

1919
import java.util.Set;
2020

@@ -25,6 +25,7 @@
2525
import org.apache.commons.logging.LogFactory;
2626
import org.jspecify.annotations.Nullable;
2727

28+
import org.springframework.boot.tomcat.TomcatEmbeddedContext;
2829
import org.springframework.boot.web.servlet.ServletContextInitializer;
2930

3031
/**
@@ -33,17 +34,17 @@
3334
*
3435
* @author Phillip Webb
3536
* @author Andy Wilkinson
36-
* @since 4.0.0
3737
*/
38-
public class TomcatStarter implements ServletContainerInitializer {
38+
class DeferredServletContainerInitializers
39+
implements ServletContainerInitializer, TomcatEmbeddedContext.DeferredStartupExceptions {
3940

40-
private static final Log logger = LogFactory.getLog(TomcatStarter.class);
41+
private static final Log logger = LogFactory.getLog(DeferredServletContainerInitializers.class);
4142

4243
private final Iterable<ServletContextInitializer> initializers;
4344

4445
private volatile @Nullable Exception startUpException;
4546

46-
public TomcatStarter(Iterable<ServletContextInitializer> initializers) {
47+
DeferredServletContainerInitializers(Iterable<ServletContextInitializer> initializers) {
4748
this.initializers = initializers;
4849
}
4950

@@ -65,8 +66,11 @@ public void onStartup(Set<Class<?>> classes, ServletContext servletContext) thro
6566
}
6667
}
6768

68-
@Nullable Exception getStartUpException() {
69-
return this.startUpException;
69+
@Override
70+
public void rethrow() throws Exception {
71+
if (this.startUpException != null) {
72+
throw this.startUpException;
73+
}
7074
}
7175

7276
}

module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/servlet/TomcatServletWebServerFactory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@
7070
import org.springframework.boot.tomcat.TomcatContextCustomizer;
7171
import org.springframework.boot.tomcat.TomcatEmbeddedContext;
7272
import org.springframework.boot.tomcat.TomcatEmbeddedWebappClassLoader;
73-
import org.springframework.boot.tomcat.TomcatStarter;
7473
import org.springframework.boot.tomcat.TomcatWebServer;
7574
import org.springframework.boot.tomcat.TomcatWebServerFactory;
7675
import org.springframework.boot.web.error.ErrorPage;
@@ -289,12 +288,13 @@ private void addJasperInitializer(TomcatEmbeddedContext context) {
289288
* @param initializers initializers to apply
290289
*/
291290
protected void configureContext(Context context, Iterable<ServletContextInitializer> initializers) {
292-
TomcatStarter starter = new TomcatStarter(initializers);
291+
DeferredServletContainerInitializers deferredInitializers = new DeferredServletContainerInitializers(
292+
initializers);
293293
if (context instanceof TomcatEmbeddedContext embeddedContext) {
294-
embeddedContext.setStarter(starter);
294+
embeddedContext.setDeferredStartupExceptions(deferredInitializers);
295295
embeddedContext.setFailCtxIfServletStartFails(true);
296296
}
297-
context.addServletContainerInitializer(starter, NO_CLASSES);
297+
context.addServletContainerInitializer(deferredInitializers, NO_CLASSES);
298298
for (LifecycleListener lifecycleListener : this.getContextLifecycleListeners()) {
299299
context.addLifecycleListener(lifecycleListener);
300300
}

0 commit comments

Comments
 (0)