diff --git a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle index 52c1e178e1b..8fe601a425b 100644 --- a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle +++ b/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' // 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[] diff --git a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle.kts b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle.kts index d59ac9d0cdb..60f7df8a934 100644 --- a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle.kts +++ b/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") // 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[] diff --git a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging.adoc b/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging.adoc index a68caa60f55..af873a18b1f 100644 --- a/build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging.adoc +++ b/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 === 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 ---- ====== -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. diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/traditional-deployment.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/traditional-deployment.adoc index ea91618e790..a81644d7e23 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/traditional-deployment.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/traditional-deployment.adoc @@ -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 org.springframework.boot - spring-boot-tomcat-runtime + spring-boot-starter-tomcat provided ---- -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' // ... } ---- diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc index b61c5659726..dfefc16d879 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc +++ b/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. 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] ---- org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc @@ -39,23 +44,70 @@ The following Maven example shows how to exclude Tomcat and include Jetty for Sp spring-boot-starter-jetty ---- ++ -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: + + +[tabs] +====== + +Maven:: ++ +[source,xml] +---- + + org.springframework.boot + spring-boot-starter-webmvc + + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + org.springframework.boot + spring-boot-starter-jetty + provided + +---- ++ -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. +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" +} +---- ++ +====== diff --git a/module/spring-boot-jetty/build.gradle b/module/spring-boot-jetty/build.gradle index 9faab9a59d4..25e314dace7 100644 --- a/module/spring-boot-jetty/build.gradle +++ b/module/spring-boot-jetty/build.gradle @@ -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") diff --git a/module/spring-boot-tomcat/build.gradle b/module/spring-boot-tomcat/build.gradle index 1ccd8d30c73..252f953b264 100644 --- a/module/spring-boot-tomcat/build.gradle +++ b/module/spring-boot-tomcat/build.gradle @@ -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") diff --git a/platform/spring-boot-dependencies/build.gradle b/platform/spring-boot-dependencies/build.gradle index 00b53bdfa3c..73d35ad6117 100644 --- a/platform/spring-boot-dependencies/build.gradle +++ b/platform/spring-boot-dependencies/build.gradle @@ -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 { "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 { "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 { "spring-boot-testcontainers", "spring-boot-thymeleaf", "spring-boot-tomcat", - "spring-boot-tomcat-runtime", "spring-boot-transaction", "spring-boot-validation", "spring-boot-web-server", diff --git a/settings.gradle b/settings.gradle index 584dce4e0f9..3d3ff598b5a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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" 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" 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" 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" diff --git a/smoke-test/spring-boot-smoke-test-tomcat-jsp/build.gradle b/smoke-test/spring-boot-smoke-test-tomcat-jsp/build.gradle index d455ac5b6e4..738079232f7 100644 --- a/smoke-test/spring-boot-smoke-test-tomcat-jsp/build.gradle +++ b/smoke-test/spring-boot-smoke-test-tomcat-jsp/build.gradle @@ -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") diff --git a/smoke-test/spring-boot-smoke-test-traditional/build.gradle b/smoke-test/spring-boot-smoke-test-traditional/build.gradle index 9fa743acf01..e3c2a1fcf52 100644 --- a/smoke-test/spring-boot-smoke-test-traditional/build.gradle +++ b/smoke-test/spring-boot-smoke-test-traditional/build.gradle @@ -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")) diff --git a/smoke-test/spring-boot-smoke-test-web-jsp/build.gradle b/smoke-test/spring-boot-smoke-test-web-jsp/build.gradle index dd6bd1fe88a..3d20bf9cd7b 100644 --- a/smoke-test/spring-boot-smoke-test-web-jsp/build.gradle +++ b/smoke-test/spring-boot-smoke-test-web-jsp/build.gradle @@ -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") diff --git a/smoke-test/spring-boot-smoke-test-web-static/build.gradle b/smoke-test/spring-boot-smoke-test-web-static/build.gradle index 47c4e5e991d..61ea11439e5 100644 --- a/smoke-test/spring-boot-smoke-test-web-static/build.gradle +++ b/smoke-test/spring-boot-smoke-test-web-static/build.gradle @@ -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") diff --git a/module/spring-boot-jetty-runtime/build.gradle b/starter/spring-boot-starter-jetty-runtime/build.gradle similarity index 63% rename from module/spring-boot-jetty-runtime/build.gradle rename to starter/spring-boot-starter-jetty-runtime/build.gradle index a911b1e52d2..188ee683708 100644 --- a/module/spring-boot-jetty-runtime/build.gradle +++ b/starter/spring-boot-starter-jetty-runtime/build.gradle @@ -15,34 +15,31 @@ */ 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: "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" exclude group: "org.eclipse.jetty", module: "jetty-jndi" - exclude group: "org.slf4j", module: "slf4j-api" + exclude group: "org.slf4j", module: "slf4j-api" } } diff --git a/starter/spring-boot-starter-jetty/build.gradle b/starter/spring-boot-starter-jetty/build.gradle index 4cdab32a453..3f401bca10d 100644 --- a/starter/spring-boot-starter-jetty/build.gradle +++ b/starter/spring-boot-starter-jetty/build.gradle @@ -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") } diff --git a/module/spring-boot-tomcat-runtime/build.gradle b/starter/spring-boot-starter-tomcat-runtime/build.gradle similarity index 77% rename from module/spring-boot-tomcat-runtime/build.gradle rename to starter/spring-boot-starter-tomcat-runtime/build.gradle index cbe5ca0a1b5..f7f2a06c8cf 100644 --- a/module/spring-boot-tomcat-runtime/build.gradle +++ b/starter/spring-boot-starter-tomcat-runtime/build.gradle @@ -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" } diff --git a/starter/spring-boot-starter-tomcat/build.gradle b/starter/spring-boot-starter-tomcat/build.gradle index 254a50eda20..e4ab73b3f82 100644 --- a/starter/spring-boot-starter-tomcat/build.gradle +++ b/starter/spring-boot-starter-tomcat/build.gradle @@ -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") } diff --git a/system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-executableWarApp.gradle b/system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-executableWarApp.gradle index 7b158712621..72a1fa79368 100644 --- a/system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-executableWarApp.gradle +++ b/system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-executableWarApp.gradle @@ -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 {