From ae90add7c7cbc3280b7631476f9a187b1d7fcb21 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 16 May 2023 12:58:32 -0700 Subject: [PATCH] Polish --- .../orm/jpa/HibernateJpaConfiguration.java | 19 ++-- .../HibernateJpaAutoConfigurationTests.java | 9 +- .../DockerComposeLifecycleManager.java | 8 +- .../docs/asciidoc/deployment/efficient.adoc | 4 + .../src/docs/asciidoc/features/testing.adoc | 4 +- .../getting-started/first-application.adoc | 102 ++++++++++-------- .../plugin/NativeImagePluginAction.java | 12 ++- 7 files changed, 92 insertions(+), 66 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index 536988a8134..d402c764822 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Supplier; import javax.sql.DataSource; @@ -37,6 +38,7 @@ import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.aot.hint.TypeHint; +import org.springframework.aot.hint.TypeHint.Builder; import org.springframework.aot.hint.TypeReference; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -250,19 +252,16 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { static class HibernateRuntimeHints implements RuntimeHintsRegistrar { + private static final Consumer INVOKE_DECLARED_CONSTRUCTORS = TypeHint + .builtWith(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + @Override public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - for (String clazz : NO_JTA_PLATFORM_CLASSES) { - hints.reflection() - .registerType(TypeReference.of(clazz), - TypeHint.builtWith(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + for (String noJtaPlatformClass : NO_JTA_PLATFORM_CLASSES) { + hints.reflection().registerType(TypeReference.of(noJtaPlatformClass), INVOKE_DECLARED_CONSTRUCTORS); } - hints.reflection() - .registerType(SpringImplicitNamingStrategy.class, - TypeHint.builtWith(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); - hints.reflection() - .registerType(CamelCaseToUnderscoresNamingStrategy.class, - TypeHint.builtWith(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + hints.reflection().registerType(SpringImplicitNamingStrategy.class, INVOKE_DECLARED_CONSTRUCTORS); + hints.reflection().registerType(CamelCaseToUnderscoresNamingStrategy.class, INVOKE_DECLARED_CONSTRUCTORS); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index 398c763532d..d1ddd7e0097 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -487,10 +487,11 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes void registersHintsForJtaClasses() { RuntimeHints hints = new RuntimeHints(); new HibernateRuntimeHints().registerHints(hints, getClass().getClassLoader()); - for (String clazz : Arrays.asList("org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform", + for (String noJtaPlatformClass : Arrays.asList( + "org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform", "org.hibernate.service.jta.platform.internal.NoJtaPlatform")) { assertThat(RuntimeHintsPredicates.reflection() - .onType(TypeReference.of(clazz)) + .onType(TypeReference.of(noJtaPlatformClass)) .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints); } } @@ -499,10 +500,10 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes void registersHintsForNamingClasses() { RuntimeHints hints = new RuntimeHints(); new HibernateRuntimeHints().registerHints(hints, getClass().getClassLoader()); - for (Class clazz : Arrays.asList(SpringImplicitNamingStrategy.class, + for (Class noJtaPlatformClass : Arrays.asList(SpringImplicitNamingStrategy.class, CamelCaseToUnderscoresNamingStrategy.class)) { assertThat(RuntimeHintsPredicates.reflection() - .onType(clazz) + .onType(noJtaPlatformClass) .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints); } } diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java index 04c7874cd5c..4b5f0871ce4 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java @@ -36,6 +36,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.core.log.LogMessage; +import org.springframework.util.Assert; /** * Manages the lifecycle for docker compose services. @@ -125,11 +126,8 @@ class DockerComposeLifecycleManager { protected DockerComposeFile getComposeFile() { DockerComposeFile composeFile = (this.properties.getFile() != null) ? DockerComposeFile.of(this.properties.getFile()) : DockerComposeFile.find(this.workingDirectory); - if (composeFile == null) { - File dir = (this.workingDirectory != null) ? this.workingDirectory : new File("."); - throw new IllegalStateException("No Docker Compose file found in directory '%s'" - .formatted(dir.toPath().toAbsolutePath().toString())); - } + Assert.state(composeFile != null, () -> "No Docker Compose file found in directory '%s'".formatted( + ((this.workingDirectory != null) ? this.workingDirectory : new File(".")).toPath().toAbsolutePath())); logger.info(LogMessage.format("Using Docker Compose file '%s'", composeFile)); return composeFile; } diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment/efficient.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment/efficient.adoc index ab3f0be2344..9064f844c7f 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment/efficient.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment/efficient.adoc @@ -1,6 +1,8 @@ [[deployment.efficient]] == Efficient deployments + + [[deployment.efficient.unpacking]] === Unpacking the Executable JAR If you are running your application from a container, you can use an executable jar, but it is also often an advantage to explode it and run it in a different way. @@ -28,6 +30,8 @@ Once you have unpacked the jar file, you can also get an extra boost to startup NOTE: Using the `JarLauncher` over the application's main method has the added benefit of a predictable classpath order. The jar contains a `classpath.idx` file which is used by the `JarLauncher` when constructing the classpath. + + [[deployment.efficient.aot]] === Using Ahead-of-time Processing With the JVM diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc index 76b1663def1..fd4f17f9230 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc @@ -1083,9 +1083,9 @@ TIP: You can use the `@ServiceConnection` annotation on `Container` fields to es You can also add <> to your declaration class. + [[features.testing.testcontainers.at-development-time.devtools]] ===== Using DevTools with Testcontainers at Development Time - When using devtools, you can annotate beans and bean methods with `@RestartScope`. Such beans won't be recreated when the devtools restart the application. This is especially useful for Testcontainer `Container` beans, as they keep their state despite the application restart. @@ -1095,6 +1095,8 @@ include::code:MyContainersConfiguration[] WARNING: If you're using Gradle and want to use this feature, you need to change the configuration of the `spring-boot-devtools` dependency from `developmentOnly` to `testImplementation`. With the default scope of `developmentOnly`, the `bootTestRun` task will not pick up changes in your code, as the devtools are not active. + + [[features.testing.utilities]] === Test Utilities A few test utility classes that are generally useful when testing your application are packaged as part of `spring-boot`. diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/getting-started/first-application.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/getting-started/first-application.adoc index 09ea3efbaea..f6e1268b630 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/getting-started/first-application.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/getting-started/first-application.adoc @@ -13,9 +13,10 @@ Doing so generates a new project structure so that you can <> section so that you can omit `version` tags for "`blessed`" dependencies. @@ -201,9 +207,10 @@ To add the necessary dependencies, edit your `pom.xml` and add the `spring-boot- If you run `mvn dependency:tree` again, you see that there are now a number of additional dependencies, including the Tomcat web server and Spring Boot itself. + + [[getting-started.first-application.dependencies.gradle]] ==== Gradle - Most Spring Boot applications use the `org.springframework.boot` Gradle plugin. This plugin provides useful defaults and Gradle tasks. The `io.spring.dependency-management` Gradle plugin provides <> so that you can omit `version` tags for "`blessed`" dependencies. @@ -213,13 +220,13 @@ Before that, we can look at what we currently have by running the following comm [source,shell,indent=0,subs="verbatim"] ---- - $ gradle dependencies + $ gradle dependencies - > Task :dependencies + > Task :dependencies - ------------------------------------------------------------ - Root project 'myproject' - ------------------------------------------------------------ + ------------------------------------------------------------ + Root project 'myproject' + ------------------------------------------------------------ ---- The `gradle dependencies` command prints a tree representation of your project dependencies. @@ -228,14 +235,15 @@ To add the necessary dependencies, edit your `build.gradle` and add the `spring- [source,gradle,indent=0,subs="verbatim"] ---- - dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - } + dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + } ---- If you run `gradle dependencies` again, you see that there are now a number of additional dependencies, including the Tomcat web server and Spring Boot itself. + [[getting-started.first-application.code]] === Writing the Code To finish our application, we need to create a single Java file. @@ -296,6 +304,8 @@ The `args` array is also passed through to expose any command-line arguments. [[getting-started.first-application.run]] === Running the Example + + [[getting-started.first-application.run.maven]] ==== Maven At this point, your application should work. @@ -329,9 +339,10 @@ If you open a web browser to `http://localhost:8080`, you should see the followi To gracefully exit the application, press `ctrl-c`. + + [[getting-started.first-application.run.gradle]] ==== Gradle - At this point, your application should work. Since you used the `org.springframework.boot` Gradle plugin, you have a useful `bootRun` goal that you can use to start the application. Type `gradle bootRun` from the root project directory to start the application. @@ -364,6 +375,7 @@ If you open a web browser to `http://localhost:8080`, you should see the followi To gracefully exit the application, press `ctrl-c`. + [[getting-started.first-application.executable-jar]] === Creating an Executable Jar We finish our example by creating a completely self-contained executable jar file that we could run in production. @@ -382,9 +394,10 @@ It can also be problematic if the same filename is used (but with different cont Spring Boot takes a <> and lets you actually nest jars directly. **** + + [[getting-started.first-application.executable-jar.maven]] ==== Maven - To create an executable jar, we need to add the `spring-boot-maven-plugin` to our `pom.xml`. To do so, insert the following lines just below the `dependencies` section: @@ -458,9 +471,10 @@ To run that application, use the `java -jar` command, as follows: As before, to exit the application, press `ctrl-c`. + + [[getting-started.first-application.executable-jar.gradle]] ==== Gradle - To create an executable jar, we need to run `gradle bootJar` from the command line, as follows: [source,shell,indent=0,subs="verbatim,attributes"] diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/NativeImagePluginAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/NativeImagePluginAction.java index 612479175d5..3cc2bf7b2b2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/NativeImagePluginAction.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/NativeImagePluginAction.java @@ -28,6 +28,7 @@ import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.file.FileCollection; +import org.gradle.api.java.archives.Manifest; import org.gradle.api.plugins.ExtensionAware; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginExtension; @@ -122,8 +123,15 @@ class NativeImagePluginAction implements PluginApplicationAction { private void configureJarManifestNativeAttribute(Project project) { project.getTasks() .named(SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class) - .configure((bootJar) -> bootJar - .manifest(((manifest) -> manifest.getAttributes().put("Spring-Boot-Native-Processed", true)))); + .configure(this::addNativeProcessedAttribute); + } + + private void addNativeProcessedAttribute(BootJar bootJar) { + bootJar.manifest(this::addNativeProcessedAttribute); + } + + private void addNativeProcessedAttribute(Manifest manifest) { + manifest.getAttributes().put("Spring-Boot-Native-Processed", true); } }