Skip to content

Commit fb33610

Browse files
committed
Automatically create developmentOnly configuration
Previously, the developmentOnly configuration, typically used for Devtools, had to be declared manually. The BootJar and BootWar tasks then had a property, excludeDevtools, that could be used to control whether or not Devtools would be excluded from the executable archive. This commit updates the reaction to the Java plugin being applied to automatically create the developmentOnly configuration. The classpaths of bootJar and bootWar are then configured not to include the contents of the developmentOnly configuration. As a result of this, the excludeDevtools property is no longer needed and has been deprecated. Its default has also been changed from true to false to make it easy to opt in to Devtools, when configured as a development-only dependency, being included in executable jars and wars by adding developmentOnly to the classpath of the archive task. Closes gh-16599
1 parent cbdc5d9 commit fb33610

21 files changed

+196
-30
lines changed

spring-boot-project/spring-boot-docs/src/docs/asciidoc/using-spring-boot.adoc

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -533,12 +533,6 @@ To include devtools support, add the module dependency to your build, as shown i
533533
.Gradle
534534
[source,groovy,indent=0,subs="attributes"]
535535
----
536-
configurations {
537-
developmentOnly
538-
runtimeClasspath {
539-
extendsFrom developmentOnly
540-
}
541-
}
542536
dependencies {
543537
developmentOnly("org.springframework.boot:spring-boot-devtools")
544538
}
@@ -548,11 +542,12 @@ NOTE: Developer tools are automatically disabled when running a fully packaged a
548542
If your application is launched from `java -jar` or if it is started from a special classloader, then it is considered a "`production application`".
549543
If that does not apply to you (i.e. if you run your application from a container), consider excluding devtools or set the `-Dspring.devtools.restart.enabled=false` system property.
550544

551-
TIP: Flagging the dependency as optional in Maven or using a custom `developmentOnly` configuration in Gradle (as shown above) is a best practice that prevents devtools from being transitively applied to other modules that use your project.
545+
TIP: Flagging the dependency as optional in Maven or using the `developmentOnly` configuration in Gradle (as shown above) prevents devtools from being transitively applied to other modules that use your project.
552546

553547
TIP: Repackaged archives do not contain devtools by default.
554-
If you want to use a <<using-boot-devtools-remote,certain remote devtools feature>>, you need to disable the `excludeDevtools` build property to include it.
555-
The property is supported with both the Maven and Gradle plugins.
548+
If you want to use a <<using-boot-devtools-remote,certain remote devtools feature>>, you need to include it.
549+
When using the Maven plugin, set the `excludeDevtools` property to `false`.
550+
When using the Gradle plugin, {spring-boot-gradle-plugin-docs}#packaging-executable-configuring-including-development-only-dependencies[configure the task's classpath to include the `developmentOnly` configuration].
556551

557552

558553

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/packaging.adoc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,11 @@ include::../gradle/packaging/boot-jar-manifest-main-class.gradle.kts[tags=main-c
149149

150150

151151

152-
[[packaging-executable-configuring-excluding-devtools]]
153-
==== Excluding Devtools
154-
By default, Spring Boot's Devtools module, `org.springframework.boot:spring-boot-devtools`, will be excluded from an executable jar or war.
155-
If you want to include Devtools in your archive set the `excludeDevtools` property to `false`:
152+
[[packaging-executable-configuring-including-development-only-dependencies]]
153+
==== Including Development-only Dependencies
154+
By default all dependencies declared in the `developmentOnly` configuration will be excluded from an executable jar or war.
155+
156+
If you want to include dependencies declared in the `developmentOnly` configuration in your archive, configure the classpath of its task to include the configuration, as shown in the following example for the `bootWar` task:
156157

157158
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
158159
.Groovy

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/asciidoc/reacting.adoc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ When Gradle's {java-plugin}[`java` plugin] is applied to a project, the Spring B
1616
4. Creates a {boot-build-image-javadoc}[`BootBuildImage`] task named `bootBuildImage` that will create a OCI image using a https://buildpacks.io[buildpack].
1717
5. Creates a {boot-run-javadoc}[`BootRun`] task named `bootRun` that can be used to run your application.
1818
6. Creates a configuration named `bootArchives` that contains the artifact produced by the `bootJar` task.
19-
7. Configures any `JavaCompile` tasks with no configured encoding to use `UTF-8`.
20-
8. Configures any `JavaCompile` tasks to use the `-parameters` compiler argument.
19+
7. Creates a configuration named `developmentOnly` for dependencies that are only required at development time, such as Spring Boot's Devtools, and should not be packaged in executable jars and wars.
20+
8. Configures any `JavaCompile` tasks with no configured encoding to use `UTF-8`.
21+
9. Configures any `JavaCompile` tasks to use the `-parameters` compiler argument.
2122

2223

2324

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-war-include-devtools.gradle

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ plugins {
55

66
bootWar {
77
mainClassName 'com.example.ExampleApplication'
8-
classpath file('spring-boot-devtools-1.2.3.RELEASE.jar')
8+
}
9+
10+
dependencies {
11+
developmentOnly files("spring-boot-devtools-1.2.3.RELEASE.jar")
912
}
1013

1114
// tag::include-devtools[]
1215
bootWar {
13-
excludeDevtools = false
16+
classpath configurations.developmentOnly
1417
}
1518
// end::include-devtools[]

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-war-include-devtools.gradle.kts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ plugins {
77

88
tasks.getByName<BootWar>("bootWar") {
99
mainClassName = "com.example.ExampleApplication"
10-
classpath(file("spring-boot-devtools-1.2.3.RELEASE.jar"))
10+
}
11+
12+
dependencies {
13+
"developmentOnly"(files("spring-boot-devtools-1.2.3.RELEASE.jar"))
1114
}
1215

1316
// tag::include-devtools[]
1417
tasks.getByName<BootWar>("bootWar") {
15-
isExcludeDevtools = false
18+
classpath(configurations["developmentOnly"])
1619
}
1720
// end::include-devtools[]

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.gradle.api.Plugin;
2828
import org.gradle.api.Project;
2929
import org.gradle.api.Task;
30+
import org.gradle.api.artifacts.Configuration;
3031
import org.gradle.api.file.FileCollection;
3132
import org.gradle.api.internal.artifacts.dsl.LazyPublishArtifact;
3233
import org.gradle.api.plugins.ApplicationPlugin;
@@ -67,6 +68,7 @@ public Class<? extends Plugin<? extends Project>> getPluginClass() {
6768
public void execute(Project project) {
6869
disableJarTask(project);
6970
configureBuildTask(project);
71+
configureDevelopmentOnlyConfiguration(project);
7072
TaskProvider<BootJar> bootJar = configureBootJarTask(project);
7173
configureBootBuildImageTask(project, bootJar);
7274
configureArtifactPublication(bootJar);
@@ -92,7 +94,8 @@ private TaskProvider<BootJar> configureBootJarTask(Project project) {
9294
bootJar.setGroup(BasePlugin.BUILD_GROUP);
9395
SourceSet mainSourceSet = javaPluginConvention(project).getSourceSets()
9496
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
95-
bootJar.classpath((Callable<FileCollection>) mainSourceSet::getRuntimeClasspath);
97+
bootJar.classpath((Callable<FileCollection>) () -> mainSourceSet.getRuntimeClasspath().minus(
98+
project.getConfigurations().getByName(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME)));
9699
bootJar.conventionMapping("mainClassName", new MainClassConvention(project, bootJar::getClasspath));
97100
});
98101
}
@@ -157,6 +160,15 @@ private void configureAdditionalMetadataLocations(JavaCompile compile) {
157160
compile.doFirst(new AdditionalMetadataLocationsConfigurer());
158161
}
159162

163+
private void configureDevelopmentOnlyConfiguration(Project project) {
164+
Configuration developmentOnly = project.getConfigurations()
165+
.create(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME);
166+
developmentOnly
167+
.setDescription("Configuration for development-only dependencies such as Spring Boot's DevTools.");
168+
project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)
169+
.extendsFrom(developmentOnly);
170+
}
171+
160172
/**
161173
* Task {@link Action} to add additional meta-data locations. We need to use an
162174
* inner-class rather than a lambda due to

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ public class SpringBootPlugin implements Plugin<Project> {
7070
*/
7171
public static final String BOOT_BUILD_IMAGE_TASK_NAME = "bootBuildImage";
7272

73+
/**
74+
* The name of the {@code developmentOnly} configuration.
75+
* @since 2.3.0
76+
*/
77+
public static final String DEVELOPMENT_ONLY_CONFIGURATION_NAME = "developmentOnly";
78+
7379
/**
7480
* The coordinates {@code (group:name:version)} of the
7581
* {@code spring-boot-dependencies} bom.

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
import org.gradle.api.Action;
2020
import org.gradle.api.Plugin;
2121
import org.gradle.api.Project;
22-
import org.gradle.api.artifacts.Configuration;
22+
import org.gradle.api.artifacts.ConfigurationContainer;
23+
import org.gradle.api.file.FileCollection;
2324
import org.gradle.api.internal.artifacts.dsl.LazyPublishArtifact;
2425
import org.gradle.api.plugins.BasePlugin;
2526
import org.gradle.api.plugins.WarPlugin;
@@ -63,12 +64,15 @@ private TaskProvider<BootWar> configureBootWarTask(Project project) {
6364
bootWar.setDescription("Assembles an executable war archive containing webapp"
6465
+ " content, and the main classes and their dependencies.");
6566
bootWar.providedClasspath(providedRuntimeConfiguration(project));
67+
bootWar.setClasspath(bootWar.getClasspath().minus(
68+
project.getConfigurations().getByName(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME)));
6669
bootWar.conventionMapping("mainClassName", new MainClassConvention(project, bootWar::getClasspath));
6770
});
6871
}
6972

70-
private Configuration providedRuntimeConfiguration(Project project) {
71-
return project.getConfigurations().getByName(WarPlugin.PROVIDED_RUNTIME_CONFIGURATION_NAME);
73+
private FileCollection providedRuntimeConfiguration(Project project) {
74+
ConfigurationContainer configurations = project.getConfigurations();
75+
return configurations.getByName(WarPlugin.PROVIDED_RUNTIME_CONFIGURATION_NAME);
7276
}
7377

7478
private void configureArtifactPublication(TaskProvider<BootWar> bootWar) {

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,21 @@ public interface BootArchive extends Task {
118118
* {@code false}.
119119
* @return {@code true} if the Devtools jar should be excluded, or {@code false} if
120120
* not
121+
* @deprecated since 2.3.0 in favour of configuring a classpath that does not include
122+
* development-only dependencies
121123
*/
122124
@Input
125+
@Deprecated
123126
boolean isExcludeDevtools();
124127

125128
/**
126129
* Sets whether or not the Devtools jar should be excluded.
127130
* @param excludeDevtools {@code true} if the Devtools jar should be excluded, or
128131
* {@code false} if not
132+
* @deprecated since 2.3.0 in favour of configuring a classpath that does not include
133+
* development-only dependencies
129134
*/
135+
@Deprecated
130136
void setExcludeDevtools(boolean excludeDevtools);
131137

132138
}

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class BootArchiveSupport {
7676

7777
private LaunchScriptConfiguration launchScript;
7878

79-
private boolean excludeDevtools = true;
79+
private boolean excludeDevtools = false;
8080

8181
BootArchiveSupport(String loaderMainClass, Spec<FileCopyDetails> librarySpec,
8282
Function<FileCopyDetails, ZipCompression> compressionResolver) {

0 commit comments

Comments
 (0)