Browse Source

Change tomcat and jetty runtime modules to starters

Change `spring-boot-tomcat-runtime` and `spring-boot-jetty-runtime`
into starter POMs and reduce the number of dependencies needed for
`spring-boot-tomcat` and `spring-boot-jetty`.

The runtime starters provide only the jars required to run the
embedded server along with the module jar itself (excluding transitive
dependencies) and `spring-boot-webserver` (excluding transitive
dependencies).

The build setup required for an executable jar is slightly different
between Maven and Gradle. For Maven, the regular module is put in the
`provided` scope. For Gradle, the regular module remains in main
configuration and the runtime jar is put in the `providedRuntime`
configuration. The reference documentation has been updated to
show how to configure things if starters are being used.

Manual testing has been performed to ensure that wars build with Maven
and Gradle work with both Tomcat and Jetty in both deployed and
`java -jar` modes.

Closes gh-48175
pull/48469/head
Phillip Webb 4 weeks ago
parent
commit
2685f4bf29
  1. 4
      build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle
  2. 2
      build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle.kts
  3. 4
      build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging.adoc
  4. 11
      documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/traditional-deployment.adoc
  5. 74
      documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc
  6. 11
      module/spring-boot-jetty/build.gradle
  7. 7
      module/spring-boot-tomcat/build.gradle
  8. 4
      platform/spring-boot-dependencies/build.gradle
  9. 4
      settings.gradle
  10. 2
      smoke-test/spring-boot-smoke-test-tomcat-jsp/build.gradle
  11. 5
      smoke-test/spring-boot-smoke-test-traditional/build.gradle
  12. 2
      smoke-test/spring-boot-smoke-test-web-jsp/build.gradle
  13. 2
      smoke-test/spring-boot-smoke-test-web-static/build.gradle
  14. 25
      starter/spring-boot-starter-jetty-runtime/build.gradle
  15. 5
      starter/spring-boot-starter-jetty/build.gradle
  16. 12
      starter/spring-boot-starter-tomcat-runtime/build.gradle
  17. 5
      starter/spring-boot-starter-tomcat/build.gradle
  18. 2
      system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-executableWarApp.gradle

4
build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle

@ -23,7 +23,7 @@ apply plugin: 'io.spring.dependency-management' @@ -23,7 +23,7 @@ apply plugin: 'io.spring.dependency-management'
// tag::dependencies[]
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web')
providedRuntime('org.springframework.boot:spring-boot-tomcat-runtime')
implementation('org.springframework.boot:spring-boot-starter-webmvc')
providedRuntime('org.springframework.boot:spring-boot-starter-tomcat-runtime')
}
// end::dependencies[]

2
build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle.kts

@ -8,6 +8,6 @@ apply(plugin = "io.spring.dependency-management") @@ -8,6 +8,6 @@ apply(plugin = "io.spring.dependency-management")
// tag::dependencies[]
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
providedRuntime("org.springframework.boot:spring-boot-tomcat-runtime")
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat-runtime")
}
// end::dependencies[]

4
build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging.adoc

@ -27,7 +27,7 @@ The `assemble` task is automatically configured to depend upon the `bootWar` tas @@ -27,7 +27,7 @@ The `assemble` task is automatically configured to depend upon the `bootWar` tas
=== Packaging Executable and Deployable Wars
A war file can be packaged such that it can be executed using `java -jar` and deployed to an external container.
To do so, the embedded servlet runtime should be added to the `providedRuntime` configuration, for example:
To do so, the embedded servlet container runtime should be added to the `providedRuntime` configuration, for example:
[tabs]
======
@ -45,7 +45,7 @@ include::example$packaging/war-container-dependency.gradle.kts[tags=dependencies @@ -45,7 +45,7 @@ include::example$packaging/war-container-dependency.gradle.kts[tags=dependencies
----
======
This ensures that the runtime is packaged in the war file's `WEB-INF/lib-provided` directory from where it will not conflict with the external container's own classes.
This ensures that the runtime jars are packaged in the war file's `WEB-INF/lib-provided` directory from where they will not conflict with the external container's own classes.
NOTE: `providedRuntime` is preferred to Gradle's `compileOnly` configuration as, among other limitations, `compileOnly` dependencies are not on the test classpath so any web-based integration tests will fail.

11
documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/traditional-deployment.adoc

@ -33,9 +33,9 @@ apply plugin: 'war' @@ -33,9 +33,9 @@ apply plugin: 'war'
----
The final step in the process is to ensure that the embedded servlet container does not interfere with the servlet container to which the war file is deployed.
To do so, you need to mark the embedded servlet runtime dependency as being provided.
If you use Maven, the following example marks the servlet runtime (Tomcat, in this case) as being provided:
For Maven, you need to mark the embedded servlet container dependency as being `provided`.
For example:
[source,xml]
----
@ -43,20 +43,21 @@ If you use Maven, the following example marks the servlet runtime (Tomcat, in th @@ -43,20 +43,21 @@ If you use Maven, the following example marks the servlet runtime (Tomcat, in th
<!-- ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-tomcat-runtime</artifactId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
----
If you use Gradle, the following example marks the servlet runtime (Tomcat, in this case) as being provided:
If you use Gradle, you need to move only the runtime dependencies into the `providedRuntime` configuration.
For example:
[source,gradle]
----
dependencies {
// ...
providedRuntime 'org.springframework.boot:spring-boot-tomcat-runtime'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat-runtime'
// ...
}
----

74
documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc

@ -18,13 +18,18 @@ Many Spring Boot starters include default embedded containers. @@ -18,13 +18,18 @@ Many Spring Boot starters include default embedded containers.
When switching to a different HTTP server, you need to swap the default dependencies for those that you need instead.
To help with this process, Spring Boot provides a separate starter for each of the supported HTTP servers.
The following Maven example shows how to exclude Tomcat and include Jetty for Spring MVC:
The following example shows how to exclude Tomcat and include Jetty for Spring MVC:
[tabs]
======
Maven::
+
[source,xml]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<artifactId>spring-boot-starter-webmvc</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
@ -39,23 +44,70 @@ The following Maven example shows how to exclude Tomcat and include Jetty for Sp @@ -39,23 +44,70 @@ The following Maven example shows how to exclude Tomcat and include Jetty for Sp
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
----
+
The following Gradle example configures the necessary dependencies and a {url-gradle-docs}/resolution_rules.html#sec:module_replacement[module replacement] to use Tomcat in place of Reactor Netty for Spring WebFlux:
Gradle::
+
[source,gradle]
----
dependencies {
implementation "org.springframework.boot:spring-boot-starter-tomcat"
implementation "org.springframework.boot:spring-boot-starter-webflux"
modules {
module("org.springframework.boot:spring-boot-starter-reactor-netty") {
replacedBy("org.springframework.boot:spring-boot-starter-tomcat", "Use Tomcat instead of Reactor Netty")
}
implementation('org.springframework.boot:spring-boot-starter-webmvc') {
// Exclude the Tomcat dependency
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
// Use Jetty instead
implementation "org.springframework.boot:spring-boot-starter-jetty"
}
----
+
======
If you are creating a war file, you can use a similar approach, but you must indicate provided dependencies:
NOTE: `spring-boot-starter-reactor-netty` is required to use the javadoc:org.springframework.web.reactive.function.client.WebClient[] class, so you may need to keep a dependency on Netty even when you need to include a different HTTP server.
[tabs]
======
Maven::
+
[source,xml]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
<exclusions>
<!-- Exclude the Tomcat dependency -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<scope>provided</scope>
</dependency>
----
+
Gradle::
+
[source,gradle]
----
dependencies {
implementation('org.springframework.boot:spring-boot-starter-webmvc') {
// Exclude the Tomcat dependency
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
// Use Jetty instead
implementation "org.springframework.boot:spring-boot-starter-jetty"
providedRuntime "org.springframework.boot:spring-boot-starter-jetty-runtime"
}
----
+
======

11
module/spring-boot-jetty/build.gradle

@ -25,17 +25,20 @@ plugins { @@ -25,17 +25,20 @@ plugins {
description = "Spring Boot Jetty"
dependencies {
api(project(":module:spring-boot-jetty-runtime"))
api(project(":module:spring-boot-web-server"))
api("jakarta.servlet:jakarta.servlet-api")
api("jakarta.websocket:jakarta.websocket-api")
api("jakarta.websocket:jakarta.websocket-client-api")
api("org.eclipse.jetty.ee11:jetty-ee11-servlets")
api("org.eclipse.jetty.ee11:jetty-ee11-webapp")
implementation("org.eclipse.jetty.compression:jetty-compression-server")
implementation("org.eclipse.jetty.compression:jetty-compression-gzip")
optional(project(":core:spring-boot-autoconfigure"))
optional(project(":module:spring-boot-actuator-autoconfigure"))
optional(project(":module:spring-boot-micrometer-metrics"))
optional("org.apache.tomcat.embed:tomcat-embed-jasper")
optional("org.eclipse.jetty:jetty-alpn-conscrypt-server")
optional("org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jakarta-server")
optional("org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jetty-server")
optional("org.eclipse.jetty.http2:jetty-http2-server")
optional("org.springframework:spring-webflux")

7
module/spring-boot-tomcat/build.gradle

@ -32,13 +32,18 @@ configurations { @@ -32,13 +32,18 @@ configurations {
dependencies {
api(project(":module:spring-boot-web-server"))
api(project(":module:spring-boot-tomcat-runtime"))
api("org.apache.tomcat.embed:tomcat-embed-core") {
exclude group: "org.apache.tomcat", module: "tomcat-annotations-api"
}
optional(project(":core:spring-boot-autoconfigure"))
optional(project(":module:spring-boot-actuator-autoconfigure"))
optional(project(":module:spring-boot-micrometer-metrics"))
optional("io.micrometer:micrometer-core")
optional("org.apache.tomcat.embed:tomcat-embed-jasper")
optional("org.apache.tomcat.embed:tomcat-embed-websocket") {
exclude group: "org.apache.tomcat", module: "tomcat-annotations-api"
}
optional("org.springframework:spring-webflux")
runtimeOnly("jakarta.annotation:jakarta.annotation-api")

4
platform/spring-boot-dependencies/build.gradle

@ -2051,7 +2051,6 @@ bom { @@ -2051,7 +2051,6 @@ bom {
"spring-boot-jdbc-test",
"spring-boot-jersey",
"spring-boot-jetty",
"spring-boot-jetty-runtime",
"spring-boot-jms",
"spring-boot-jooq",
"spring-boot-jooq-test",
@ -2180,6 +2179,7 @@ bom { @@ -2180,6 +2179,7 @@ bom {
"spring-boot-starter-jersey",
"spring-boot-starter-jersey-test",
"spring-boot-starter-jetty",
"spring-boot-starter-jetty-runtime",
"spring-boot-starter-jms",
"spring-boot-starter-jms-test",
"spring-boot-starter-jooq",
@ -2245,6 +2245,7 @@ bom { @@ -2245,6 +2245,7 @@ bom {
"spring-boot-starter-thymeleaf",
"spring-boot-starter-thymeleaf-test",
"spring-boot-starter-tomcat",
"spring-boot-starter-tomcat-runtime",
"spring-boot-starter-validation",
"spring-boot-starter-validation-test",
"spring-boot-starter-web",
@ -2266,7 +2267,6 @@ bom { @@ -2266,7 +2267,6 @@ bom {
"spring-boot-testcontainers",
"spring-boot-thymeleaf",
"spring-boot-tomcat",
"spring-boot-tomcat-runtime",
"spring-boot-transaction",
"spring-boot-validation",
"spring-boot-web-server",

4
settings.gradle

@ -137,7 +137,6 @@ include "module:spring-boot-jdbc" @@ -137,7 +137,6 @@ include "module:spring-boot-jdbc"
include "module:spring-boot-jdbc-test"
include "module:spring-boot-jersey"
include "module:spring-boot-jetty"
include "module:spring-boot-jetty-runtime"
include "module:spring-boot-jms"
include "module:spring-boot-jooq"
include "module:spring-boot-jooq-test"
@ -188,7 +187,6 @@ include "module:spring-boot-sql" @@ -188,7 +187,6 @@ include "module:spring-boot-sql"
include "module:spring-boot-test-classic-modules"
include "module:spring-boot-thymeleaf"
include "module:spring-boot-tomcat"
include "module:spring-boot-tomcat-runtime"
include "module:spring-boot-transaction"
include "module:spring-boot-validation"
include "module:spring-boot-web-server"
@ -283,6 +281,7 @@ include "starter:spring-boot-starter-jdbc-test" @@ -283,6 +281,7 @@ include "starter:spring-boot-starter-jdbc-test"
include "starter:spring-boot-starter-jersey"
include "starter:spring-boot-starter-jersey-test"
include "starter:spring-boot-starter-jetty"
include "starter:spring-boot-starter-jetty-runtime"
include "starter:spring-boot-starter-jms"
include "starter:spring-boot-starter-jms-test"
include "starter:spring-boot-starter-jooq"
@ -349,6 +348,7 @@ include "starter:spring-boot-starter-test-classic" @@ -349,6 +348,7 @@ include "starter:spring-boot-starter-test-classic"
include "starter:spring-boot-starter-thymeleaf"
include "starter:spring-boot-starter-thymeleaf-test"
include "starter:spring-boot-starter-tomcat"
include "starter:spring-boot-starter-tomcat-runtime"
include "starter:spring-boot-starter-validation"
include "starter:spring-boot-starter-validation-test"
include "starter:spring-boot-starter-web"

2
smoke-test/spring-boot-smoke-test-tomcat-jsp/build.gradle

@ -29,7 +29,7 @@ configurations { @@ -29,7 +29,7 @@ configurations {
dependencies {
implementation(project(":starter:spring-boot-starter-webmvc"))
providedRuntime(project(":module:spring-boot-tomcat-runtime"))
providedRuntime(project(":starter:spring-boot-starter-tomcat-runtime"))
providedRuntime("org.glassfish.web:jakarta.servlet.jsp.jstl")
providedRuntime("org.apache.tomcat.embed:tomcat-embed-jasper")

5
smoke-test/spring-boot-smoke-test-traditional/build.gradle

@ -27,9 +27,10 @@ configurations { @@ -27,9 +27,10 @@ configurations {
}
dependencies {
implementation(project(":starter:spring-boot-starter-webmvc"))
implementation(project(":starter:spring-boot-starter"))
implementation(project(":module:spring-boot-webmvc"))
providedRuntime(project(":module:spring-boot-tomcat-runtime"))
providedRuntime(project(":starter:spring-boot-starter-tomcat-runtime"))
providedRuntime("org.apache.tomcat.embed:tomcat-embed-jasper")
testImplementation(project(":module:spring-boot-resttestclient"))

2
smoke-test/spring-boot-smoke-test-web-jsp/build.gradle

@ -29,7 +29,7 @@ configurations { @@ -29,7 +29,7 @@ configurations {
dependencies {
implementation(project(":starter:spring-boot-starter-webmvc"))
providedRuntime(project(":module:spring-boot-tomcat-runtime"))
providedRuntime(project(":starter:spring-boot-starter-tomcat-runtime"))
providedRuntime("org.apache.tomcat.embed:tomcat-embed-jasper")
providedRuntime("org.glassfish.web:jakarta.servlet.jsp.jstl")

2
smoke-test/spring-boot-smoke-test-web-static/build.gradle

@ -29,7 +29,7 @@ configurations { @@ -29,7 +29,7 @@ configurations {
dependencies {
implementation(project(":starter:spring-boot-starter-webmvc"))
providedRuntime(project(":module:spring-boot-tomcat-runtime"))
providedRuntime( project(":starter:spring-boot-starter-tomcat-runtime"))
runtimeOnly("org.webjars:bootstrap:3.0.3")
runtimeOnly("org.webjars:jquery:2.0.3-1")

25
module/spring-boot-jetty-runtime/build.gradle → starter/spring-boot-starter-jetty-runtime/build.gradle

@ -15,30 +15,27 @@ @@ -15,30 +15,27 @@
*/
plugins {
id "java-library"
id "org.springframework.boot.deployed"
id "org.springframework.boot.starter"
}
description = "Spring Boot Jetty Runtime"
description = "Starter for the Jetty runtime"
dependencies {
api("org.apache.tomcat.embed:tomcat-embed-el")
api("org.eclipse.jetty.compression:jetty-compression-gzip") {
exclude group: "org.slf4j", module: "slf4j-api"
}
api("org.eclipse.jetty.compression:jetty-compression-server") {
exclude group: "org.slf4j", module: "slf4j-api"
api(project(":module:spring-boot-jetty")) {
transitive = false
}
api("org.eclipse.jetty.ee11:jetty-ee11-servlets") {
exclude group: "org.slf4j", module: "slf4j-api"
}
api("org.eclipse.jetty.ee11:jetty-ee11-webapp") {
exclude group: "org.slf4j", module: "slf4j-api"
api(project(":module:spring-boot-web-server")) {
transitive = false
}
api("jakarta.servlet:jakarta.servlet-api")
api("jakarta.websocket:jakarta.websocket-api")
api("jakarta.websocket:jakarta.websocket-client-api")
api("org.apache.tomcat.embed:tomcat-embed-el")
api("org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jakarta-server") {
exclude group: "jakarta.el", module: "jakarta.el-api"
exclude group: "org.eclipse.jetty", module: "jetty-jndi"
exclude group: "org.slf4j", module: "slf4j-api"
exclude group: "jakarta.annotation", module: "jakarta.annotation-api"
}
api("org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jetty-server") {
exclude group: "jakarta.el", module: "jakarta.el-api"

5
starter/spring-boot-starter-jetty/build.gradle

@ -22,5 +22,10 @@ description = "Starter for using Jetty as the embedded servlet container" @@ -22,5 +22,10 @@ description = "Starter for using Jetty as the embedded servlet container"
dependencies {
api(project(":starter:spring-boot-starter"))
api(project(":starter:spring-boot-starter-jetty-runtime"))
api(project(":module:spring-boot-jetty"))
api("org.slf4j:slf4j-api")
api("jakarta.annotation:jakarta.annotation-api")
}

12
module/spring-boot-tomcat-runtime/build.gradle → starter/spring-boot-starter-tomcat-runtime/build.gradle

@ -15,13 +15,19 @@ @@ -15,13 +15,19 @@
*/
plugins {
id "java-library"
id "org.springframework.boot.deployed"
id "org.springframework.boot.starter"
}
description = "Spring Boot Tomcat Runtime"
description = "Starter for the Tomcat runtime"
dependencies {
api(project(":module:spring-boot-tomcat")) {
transitive = false
}
api(project(":module:spring-boot-web-server")) {
transitive = false
}
api("jakarta.annotation:jakarta.annotation-api")
api("org.apache.tomcat.embed:tomcat-embed-core") {
exclude group: "org.apache.tomcat", module: "tomcat-annotations-api"
}

5
starter/spring-boot-starter-tomcat/build.gradle

@ -18,10 +18,11 @@ plugins { @@ -18,10 +18,11 @@ plugins {
id "org.springframework.boot.starter"
}
description = "Starter for using Tomcat"
description = "Starter for using Tomcat as the embedded servlet container"
dependencies {
api(project(":starter:spring-boot-starter"))
api(project(":starter:spring-boot-starter-tomcat-runtime"))
api(project(":module:spring-boot-tomcat"))
api("jakarta.annotation:jakarta.annotation-api")
}

2
system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-executableWarApp.gradle

@ -38,7 +38,7 @@ repositories { @@ -38,7 +38,7 @@ repositories {
dependencies {
implementation("org.springframework.boot:spring-boot-starter-webmvc:{bootVersion}")
providedRuntime("org.springframework.boot:spring-boot-tomcat-runtime:{bootVersion}")
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat-runtime:{bootVersion}")
}
bootWar {

Loading…
Cancel
Save