From fb736e8427c3bf0bf797164b331702722a9ee2ce Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sun, 16 Oct 2022 16:43:35 -0700 Subject: [PATCH] Add native image reference documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update reference documentation with a new "native image" section. This commit includes some work derived from the "Spring Native" project documentation written by Andy Clement, Sébastien Deleuze, Filip Hanik, Dave Syer, Esteban Ginez, Jay Bryant, Brian Clozel, Stéphane Nicoll, and Josh Long. Closes gh-32582 Co-authored-by: Moritz Halbritter --- .../spring-boot-docs/build.gradle | 1 + .../src/docs/asciidoc/attributes.adoc | 3 + .../docs/asciidoc/deployment/whats-next.adoc | 2 +- .../src/docs/asciidoc/documentation.adoc | 2 + .../asciidoc/documentation/native-images.adoc | 9 + .../getting-started/system-requirements.adoc | 21 ++ .../src/docs/asciidoc/index.adoc | 1 + .../src/docs/asciidoc/index.singleadoc | 2 + .../src/docs/asciidoc/native-image.adoc | 16 ++ .../native-image/advanced-topics.adoc | 166 +++++++++++ .../developing-your-first-application.adoc | 257 ++++++++++++++++++ .../introducing-graalvm-native-images.adoc | 133 +++++++++ .../testing-native-applications.adoc | 109 ++++++++ .../asciidoc/native-image/whats-next.adoc | 8 + .../advanced/customhints/MyClass.java | 25 ++ .../advanced/customhints/MyInterface.java | 24 ++ .../advanced/customhints/MyRuntimeHints.java | 44 +++ .../customhints/MySerializableClass.java | 23 ++ .../testing/MyRuntimeHintsTests.java | 36 +++ .../MyProperties.java | 60 ++++ .../sampleapplication/MyApplication.java | 37 +++ .../sourcecodegeneration/MyBean.java | 21 ++ .../sourcecodegeneration/MyConfiguration.java | 30 ++ .../MyConfiguration__BeanDefinitions.java | 41 +++ 24 files changed, 1070 insertions(+), 1 deletion(-) create mode 100644 spring-boot-project/spring-boot-docs/src/docs/asciidoc/documentation/native-images.adoc create mode 100644 spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image.adoc create mode 100644 spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/advanced-topics.adoc create mode 100644 spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/developing-your-first-application.adoc create mode 100644 spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/introducing-graalvm-native-images.adoc create mode 100644 spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/testing-native-applications.adoc create mode 100644 spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/whats-next.adoc create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyClass.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyInterface.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyRuntimeHints.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MySerializableClass.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/testing/MyRuntimeHintsTests.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/nestedconfigurationproperties/MyProperties.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/developingyourfirstapplication/sampleapplication/MyApplication.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyBean.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration__BeanDefinitions.java diff --git a/spring-boot-project/spring-boot-docs/build.gradle b/spring-boot-project/spring-boot-docs/build.gradle index 6c1c9939fee..672277d8304 100644 --- a/spring-boot-project/spring-boot-docs/build.gradle +++ b/spring-boot-project/spring-boot-docs/build.gradle @@ -317,6 +317,7 @@ tasks.withType(org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask) { "spring-integration-version": versionConstraints["org.springframework.integration:spring-integration-core"], "spring-kafka-version": versionConstraints["org.springframework.kafka:spring-kafka"], "spring-security-version": securityVersion, + "native-build-tools-version": nativeBuildToolsVersion, "spring-webservices-version": versionConstraints["org.springframework.ws:spring-ws-core"], "remote-spring-application-output": runRemoteSpringApplicationExample.outputs.files.singleFile, "spring-application-output": runSpringApplicationExample.outputs.files.singleFile, diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/attributes.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/attributes.adoc index 3c56f98cc74..c2f141786db 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/attributes.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/attributes.adoc @@ -110,3 +110,6 @@ :micrometer-concepts-docs: {micrometer-docs}/concepts :micrometer-registry-docs: {micrometer-docs}/registry :tomcat-docs: https://tomcat.apache.org/tomcat-9.0-doc +:graal-version: 22.2 +:graal-native-image-docs: https://www.graalvm.org/{graal-version}/reference-manual/native-image +:liberica-nik-download: https://bell-sw.com/pages/downloads/native-image-kit/ diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment/whats-next.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment/whats-next.adoc index ce0bf651c98..a7b83277286 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment/whats-next.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment/whats-next.adoc @@ -4,4 +4,4 @@ See the https://www.cloudfoundry.org/[Cloud Foundry], https://www.heroku.com/[He These are just four of the most popular Java PaaS providers. Since Spring Boot is so amenable to cloud-based deployment, you can freely consider other providers as well. -The next section goes on to cover the _<>_, or you can jump ahead to read about _<>_. +The next section goes on to cover the _<>_, or you can jump ahead to read about the _<>_ or our _<>_. diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/documentation.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/documentation.adoc index b273d89ec60..77d298a6035 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/documentation.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/documentation.adoc @@ -32,4 +32,6 @@ include::documentation/io.adoc[] include::documentation/container-images.adoc[] +include::documentation/native-images.adoc[] + include::documentation/advanced.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/documentation/native-images.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/documentation/native-images.adoc new file mode 100644 index 00000000000..f19f7437228 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/documentation/native-images.adoc @@ -0,0 +1,9 @@ +[[documentation.native-images]] +== GraalVM Native Images +Spring Boot applications can be converted into native executables using GraalVM. +You can read more about our native image support here: + +* *GraalVM Native Images:* <> | <> | <> +* *Getting Started:* <> | <> +* *Testing:* <> | <> +* *Advanced Topics:* <> | <> | <> diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/getting-started/system-requirements.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/getting-started/system-requirements.adoc index aee9bff8369..0f53ec2806e 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/getting-started/system-requirements.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/getting-started/system-requirements.adoc @@ -35,3 +35,24 @@ Spring Boot supports the following embedded servlet containers: |=== You can also deploy Spring Boot applications to any servlet 5.0+ compatible container. + + + +[[getting-started.system-requirements.graal]] +=== GraalVM Native Images +Spring Boot applications can be <> using using Graal {graal-version} or above. + +Images can be created using the https://github.com/graalvm/native-build-tools[native build tools] Gradle/Maven plugins or `native-image` tool provided by GraalVM. +You can also create native images using the the https://github.com/paketo-buildpacks/native-image[native-image Paketo buildpack]. + +The following versions are supported: + +|=== +| Name | Version + +| GraalVM Community +| {graal-version} + +| Native Build Tools +| {native-build-tools-version} +|=== diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/index.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/index.adoc index ff7d6777580..c086e382868 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/index.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/index.adoc @@ -23,6 +23,7 @@ The reference documentation consists of the following sections: <> :: Efficient container images and Building container images with Dockerfiles and Cloud Native Buildpacks. <> :: Monitoring, Metrics, Auditing, and more. <> :: Deploying to the Cloud, and Installing as a Unix application. +<> :: Create a native executable from your application using GraalVM <> :: Installing the CLI, Using the CLI, Configuring the CLI, and more. <> :: Maven Plugin, Gradle Plugin, Antlib, and more. <> :: Application Development, Configuration, Embedded Servers, Data Access, and many more. diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/index.singleadoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/index.singleadoc index 2d91531be19..debab3c58fa 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/index.singleadoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/index.singleadoc @@ -39,6 +39,8 @@ include::actuator.adoc[leveloffset=+1] include::deployment.adoc[leveloffset=+1] +include::native-image.adoc[leveloffset=+1] + include::cli.adoc[leveloffset=+1] include::build-tool-plugins.adoc[leveloffset=+1] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image.adoc new file mode 100644 index 00000000000..80a6b732ea9 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image.adoc @@ -0,0 +1,16 @@ +[[native-image]] += GraalVM Native Image Support +include::attributes.adoc[] + +https://www.graalvm.org/native-image/[GraalVM Native Images] are standalone executables that can be generated by processing compiled Java applications ahead-of-time. +Native Images generally have a smaller memory footprint and start faster than their JVM counterparts. + +include::native-image/introducing-graalvm-native-images.adoc[] + +include::native-image/developing-your-first-application.adoc[] + +include::native-image/testing-native-applications.adoc[] + +include::native-image/advanced-topics.adoc[] + +include::native-image/whats-next.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/advanced-topics.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/advanced-topics.adoc new file mode 100644 index 00000000000..20dc8b5a27b --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/advanced-topics.adoc @@ -0,0 +1,166 @@ +[[native-image.advanced]] +== Advanced Native Images Topics + + + +[[native-image.advanced.nested-configuration-properties]] +=== Nested Configuration Properties +Reflection hints are automatically created for configuration properties by Spring's ahead-of-time engine. +Nested configuration properties, however, *must* be annotated with `@NestedConfigurationProperty`, otherwise they won't be detected and will not be bindable. + +include::code:MyProperties[] + +The example above produces configuration properties for `my.properties.name` and `my.properties.nested.number`. +Without the `@NestedConfigurationProperty` annotation on the `nested` field, the `my.properties.nested.number` property would not be bindable in a native image. + +NOTE: Please use public getters / setters, otherwise the properties won't be bindable. + + + +[[native-image.advanced.converting-executable-jars]] +=== Converting a Spring Boot Executable JAR +It is possible to convert a Spring Boot <> into a native image as long at the jar contains the AOT generated assets. +This can be useful for a number of reasons, including: + +* You can keeping your regular JVM pipeline and turn the JVM application into a native image on your CI/CD platform. +* As `native-image` https://github.com/oracle/graal/issues/407[does not support cross-compilation], you can keep an OS neutral deployment artifact which you convert later to different OS architectures. + +You can convert a Spring Boot executable jar into a native image using buildpacks, or the `native-image` tool that is shipped with GraalVM. + +NOTE: Your executable JAR must include AOT generated assets such as generated classes and JSON hint files. + + + +[[native-image.advanced.converting-executable-jars.buildpacks]] +==== Using Buildpacks +Spring Boot applications usually use Buildpacks via the Maven (`mvn spring-boot:build-image`), or Gradle (`gradle bootBuildImage`) integrations. +You can, however, also use https://buildpacks.io//docs/tools/pack/[`pack`] to turn an AOT processed Spring Boot executable JAR into a native container image. + + +First, make sure that a Docker daemon is available (see https://docs.docker.com/installation/#installation[Get Docker] for more details). +https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user[Configure it to allow non-root user] if you are on Linux. + +You also need to install `pack` by following https://buildpacks.io//docs/tools/pack/#install[the installation guide on buildpacks.io]. + +Assuming an AOT processed Spring Boot executable JAR built as `myproject-0.0.1-SNAPSHOT.jar` is in the `target` directory, run: + +[source,shell,indent=0,subs="verbatim"] +---- + $ pack build --builder paketobuildpacks/builder:tiny \ + --path target/myproject-0.0.1-SNAPSHOT.jar \ + --env 'BP_NATIVE_IMAGE=true' \ + my-application:0.0.1-SNAPSHOT +---- + +NOTE: You do not need to have a local GraalVM installation to generate an image in this way. + +Once `pack` has finished, you can launch the application using `docker run`: + +[source,shell,indent=0,subs="verbatim"] +---- + $ docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT +---- + + + +[[native-image.advanced.converting-executable-jars.native-image]] +==== Using GraalVM native-image +Another option to turn an AOT processed Spring Boot executable JAR into a native executable is to use the GraalVM `native-image` tool. +For this to work, you'll need a GraalVM distribution on your machine. +You can either download it manually on the {liberica-nik-download}[Liberica Native Image Kit page] or you can use a download manager like SDKMAN!. + +Assuming an AOT processed Spring Boot executable JAR built as `myproject-0.0.1-SNAPSHOT.jar` is in the `target` directory, run: + +[source,shell,indent=0,subs="verbatim"] +---- + $ rm -rf target/native + $ mkdir -p target/native + $ cd target/native + $ jar -xvf ../myproject-0.0.1-SNAPSHOT.jar + $ native-image -H:Name=myproject @META-INF/native-image/argfile -cp .:BOOT-INF/classes:`find BOOT-INF/lib | tr '\n' ':'` + $ mv myproject ../ +---- + +NOTE: These commands work on Linux or MacOS machines, you will need to adapt them for Windows. + +TIP: The `@META-INF/native-image/argfile` might not be packaged in your jar. +It is only included when reachability metadata overrides are needed. + +WARNING: The `native-image` `-cp` flag does not not accept wildcards. +You need to ensure that all jars are listed (the command above uses `find` and `tr` to do this). + + + +[[native-image.advanced.using-the-tracing-agent]] +=== Using the Tracing Agent +The GraalVM native image https://www.graalvm.org/reference-manual/native-image/Agent/[tracing agent] allows you to intercept reflection, resources or proxy usage on the JVM in order to generate the related hints. +Spring should generate most of these hints automatically, but the tracing agent can be used to quickly identify the missing entries. + +When using the agent to generate hints for a native image, there are a couple of approaches: + +* Launch the application directly and exercise it. +* Run application tests to exercise the application. + +The first option is interesting for identifying the missing hints when a library or a pattern is not recognized by Spring. + +The second option sounds more appealing for a repeatable setup, but by default the generated hints will include anything required by the test infrastructure. +Some of these will be unnecessary when the application runs for real. +To address this problem the agent supports an access-filter file that will cause certain data to be excluded from the generated output. + + + +[[native-image.advanced.using-the-tracing-agent.launch]] +==== Launch the Application Directly +Use the following command to launch the application with the native image tracing agent attached: + +[source,shell,indent=0,subs="verbatim,attributes"] +---- + $ java -Dspring.aot.enabled=true \ + -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/ \ + -jar target/myproject-0.0.1-SNAPSHOT.jar +---- + +Now you can exercise the code paths you want to have hints for and then stop the application with `ctrl-c`. + +On application shutdown the native image tracing agent will write the hint files to the given config output directory. +You can either manually inspect these files, or use them as input to the native image build process. +To use them as input, copy them into the `src/main/resources/META-INF/native-image/` directory. +The next time you build the native image, GraalVM will take these files into consideration. + +There are more advanced options which can be set on the native image tracing agent, for example filtering the recorded hints by caller classes, etc. +For further reading, please see https://www.graalvm.org/reference-manual/native-image/Agent/[the official documentation]. + + + +[[native-image.advanced.custom-hints]] +=== Custom Hints +If you need to provide your own hints for reflection, resources, serialization, proxy usage etc. you can use the `RuntimeHintsRegistrar` API. +Create a class that implements the `RuntimeHintsRegistrar` interface, then make appropriate calls to the provided `RuntimeHints` instance: + +include::code:MyRuntimeHints[] + +You can then use `@ImportRuntimeHints` on any `@Configuration` class (for example your `@SpringBootApplication` annotated application class) to activate those hints. + + + +[[native-image.advanced.custom-hints.testing]] +==== Testing custom hints +The `RuntimeHintsPredicates` API can be used to test your hints. +The API provides methods that build a `Predicate` that can be used to test a `RuntimeHints` instance. + +If you're using AssertJ, your test would look like this: + +include::code:MyRuntimeHintsTests[] + + + +[[native-image.advanced.known-limitations]] +=== Known Limitations +GraalVM native images are an evolving technology and not all libraries provide support. +The GraalVM community is helping by providing https://github.com/oracle/graalvm-reachability-metadata[reachability metadata] for projects that don't yet ship their own. +Spring itself doesn't contain hints for 3rd party libraries and instead relies on the reachability metadata project. + +If you encounter problems when generating native images for Spring Boot applications, please check the {github-wiki}/Known-GraalVM-Native-Image-Limitations[Known GraalVM Native Image Limitations] page of the Spring Boot wiki. +You can also contribute issues to the https://github.com/spring-projects/spring-aot-smoke-tests[spring-aot-smoke-tests] project on GitHub which is used to confirm that common application types are working as expected. + +If you find a library which doesn't work with GraalVM, please raise an issue on the https://github.com/oracle/graalvm-reachability-metadata[reachability metadata project]. diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/developing-your-first-application.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/developing-your-first-application.adoc new file mode 100644 index 00000000000..a73c5eb6f3a --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/developing-your-first-application.adoc @@ -0,0 +1,257 @@ +[[native-image.developing-your-first-application]] +== Developing Your First GraalVM Native Application +Now that we have a good overview of GraalVM Native Images and how Spring's ahead-of-time engine works, we can look at how to actually create them. + +There are two main ways to build a Spring Boot native image application: + +* Using Spring Boot Buildpacks support to generate a lightweight container containing a native executable. +* Using GraalVM Native Build Tools to generate a native executable. + +TIP: The easiest way to start a new native Spring Boot project is to go to https://start.spring.io[start.spring.io], add the "`GraalVM Native Support`" dependency and generate the project. +The included `HELP.md` file will provide getting started hints. + + + +[[native-image.developing-your-first-application.sample-application]] +=== Sample Application +We need an example application that we can use to create our native image. +For our purposes, the simple "`Hello World!`" web application that's covered in the "`<>`" section will suffice. + +To recap, our main application code looks like this: + +include::code:MyApplication[] + +This application uses Spring MVC and embedded Tomcat, both of which have been tested and verified to work with GraalVM native images. + + + +[[native-image.developing-your-first-application.buildpacks]] +=== Building a Native Image Using Buildpacks +Spring Boot includes buildpack support for native images directly for both Maven and Gradle. +This means you can just type a single command and quickly get a sensible image into your locally running Docker daemon. +The resulting image doesn't contain a JVM, instead the native image is compiled statically. +This leads to smaller images. + +NOTE: The builder used for the images is `builder:tiny`. +It has small footprint and reduced surface attack, but you can also use `builder:base` or `builder:full` to have more tools available in the image for an improved developer experience. + + + +[[native-image.developing-your-first-application.buildpacks.system-requirements]] +==== System Requirements +Docker should be installed, see https://docs.docker.com/installation/#installation[Get Docker] for more details. +https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user[Configure it to allow non-root user] if you are on Linux. + +NOTE: You can run `docker run hello-world` (without `sudo`) to check the Docker daemon is reachable as expected. +Check the {spring-boot-maven-plugin-docs}/#build-image-docker-daemon[Maven] or {spring-boot-gradle-plugin-docs}/#build-image-docker-daemon[Gradle] Spring Boot plugin documentation for more details. + +TIP: On MacOS, it is recommended to increase the memory allocated to Docker to at least `8GB`, and potentially add more CPUs as well. +See this https://stackoverflow.com/questions/44533319/how-to-assign-more-memory-to-docker-container/44533437#44533437[Stackoverflow answer] for more details. +On Microsoft Windows, make sure to enable the https://docs.docker.com/docker-for-windows/wsl/[Docker WSL 2 backend] for better performance. + + + +[[native-image.developing-your-first-application.buildpacks.maven]] +==== Using Maven +To build a native image container using Maven you should ensure that your `pom.xml` file uses the `spring-boot-starter-parent`. +You should have a `` section that looks like this: + +[source,xml,indent=0,subs="verbatim,attributes"] +---- + + org.springframework.boot + spring-boot-starter-parent + {spring-boot-version} + +---- + +The `spring-boot-starter-parent` declares a `native` profile that configures the executions that need to run in order to create a native image. +You can activate profiles using the `-P` flag on the command line. + +TIP: If you don't want to use `spring-boot-starter-parent` you'll need to configure executions for the `process-aot` goal from Spring Boot's plugin and the `add-reachability-metadata` goal from the Native Build Tools plugin. + +To build the image, you can run the `spring-boot:build-image` goal with the `native` profile active: + +[source,shell,indent=0,subs="verbatim"] +---- + $ mvn -Pnative spring-boot:build-image +---- + +NOTE: Currently, you need a local GraalVM installation to build an image with Maven. +This will be solved in the future, see https://github.com/graalvm/native-build-tools/issues/327[native-build-tools issue #327] for details. + + + +[[native-image.developing-your-first-application.buildpacks.gradle]] +==== Using Gradle +The Spring Boot Gradle plugin automatically configures AOT tasks when the GraalVM Native Image plugin is applied. +You should check that your gradle build contains a `plugins` block that includes `org.graalvm.buildtools.native`. + +As long as the `org.graalvm.buildtools.native` plugin is applied, the `bootBuildImage` task will generate a native image rather than a JVM one. +You can run the task using: + +[source,shell,indent=0,subs="verbatim"] +---- + $ gradle bootBuildImage +---- + + + +[[native-image.developing-your-first-application.buildpacks.running]] +==== Running the example +One you have run the appropriate build command, your a Docker image should be available. +You can start your application using `docker run`: + +[source,shell,indent=0,subs="verbatim"] +---- + $ docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT +---- + +You should see output similar to the following: + +[source,shell,indent=0,subs="verbatim,attributes"] +---- + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ + ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v{spring-boot-version}) + ....... . . . + ....... . . . (log output here) + ....... . . . + ........ Started MyApplication in 0.08 seconds (process running for 0.095) +---- + +NOTE: The startup time differs from machine to machine, but it should be much faster than a Spring Boot application running on a JVM. + +If you open a web browser to `http://localhost:8080`, you should see the following output: + +[indent=0] +---- + Hello World! +---- + +To gracefully exit the application, press `ctrl-c`. + + + +[[native-image.developing-your-first-application.native-build-tools]] +=== Building a Native Image using Native Build Tools +If you want to generate a native executable directly without using Docker, you can use GraalVM Native Build Tools. +Native Build Tools are plugins shipped by GraalVM for both Maven and Gradle. +You can use them to perform a variety of GraalVM tasks, including generating a native image. + + + +[[native-image.developing-your-first-application.native-build-tools.prerequisites]] +==== Prerequisites +To build a native image using the Native Build Tools, you'll need a GraalVM distribution on your machine. +You can either download it manually on the {liberica-nik-download}[Liberica Native Image Kit page], or you can use a download manager like SDKMAN!. + + + +[[native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos]] +===== Linux and MacOS + +To install the native image compiler on MacOS or Linux, we recommend using SDKMAN!. +Get SDKMAN! from https://sdkman.io and install the Liberica GraalVM distribution by using the following commands: + +[source,shell,indent=0,subs="verbatim,attributes"] +---- + $ sdk install java 22.2.r17-nik + $ sdk use java 22.2.r17-nik +---- + +Verify that the correct version has been configured by checking the output of `java -version`: + +[source,shell,indent=0,subs="verbatim,attributes"] +---- + $ java -version + openjdk version "17.0.4" 2022-07-19 LTS + OpenJDK Runtime Environment GraalVM 22.2.0 (build 17.0.4+8-LTS) + OpenJDK 64-Bit Server VM GraalVM 22.2.0 (build 17.0.4+8-LTS, mixed mode) +---- + + + +[[native-image.developing-your-first-application.native-build-tools.prerequisites.windows]] +===== Windows +On Windows, follow https://medium.com/graalvm/using-graalvm-and-native-image-on-windows-10-9954dc071311[these instructions] to install either https://www.graalvm.org/downloads/[GraalVM] or https://bell-sw.com/pages/downloads/native-image-kit/[Liberica Native Image Kit], Visual Studio Build Tools and Windows SDK. +Due to the https://docs.microsoft.com/en-US/troubleshoot/windows-client/shell-experience/command-line-string-limitation[Windows related command-line maximum length], make sure to use x64 Native Tools Command Prompt instead of the regular Windows command line to run Maven or Gradle plugins. + + + +[[native-image.developing-your-first-application.native-build-tools.maven]] +==== Using Maven +As with the <>, you need to make sure that you're using `spring-boot-starter-parent` in order to inherit the `native` profile. + +With the `native` profile active, you can invoke the `native:compile` goal to trigger `native-image` compilation: + +[source,shell,indent=0,subs="verbatim"] +---- + $ mvn -Pnative native:compile +---- + +The native image executable can be found in the `target` directory. + + + +[[native-image.developing-your-first-application.native-build-tools.gradle]] +==== Using Gradle +When the Native Build Tools Gradle plugin is applied to your project, the Spring Boot Gradle plugin will automatically trigger Spring's AOT engine. +Task dependencies are automatically configured, so you can just run the standard `nativeCompile` task to generate a native image: + +[source,shell,indent=0,subs="verbatim"] +---- + $ gradle nativeCompile +---- + +The native image executable can be found in the `build/native/nativeCompile` directory. + + + +[[native-image.developing-your-first-application.native-build-tools.running]] +==== Running the Example +At this point, your application should work, you can now start the application by running it directly: + +[source,shell,indent=0,subs="verbatim",role="primary"] +.Maven +---- + $ target/myproject +---- + +[source,shell,indent=0,subs="verbatim",role="secondary"] +.Gradle +---- + $ build/native/nativeCompile/myproject +---- + +You should see output similar to the following: + +[source,shell,indent=0,subs="verbatim,attributes"] +---- + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ + ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v{spring-boot-version}) + ....... . . . + ....... . . . (log output here) + ....... . . . + ........ Started MyApplication in 0.08 seconds (process running for 0.095) +---- + +NOTE: The startup time differs from machine to machine, but it should be much faster than a Spring Boot application running on a JVM. + +If you open a web browser to `http://localhost:8080`, you should see the following output: + +[indent=0] +---- + Hello World! +---- + +To gracefully exit the application, press `ctrl-c`. diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/introducing-graalvm-native-images.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/introducing-graalvm-native-images.adoc new file mode 100644 index 00000000000..4f82c752aad --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/introducing-graalvm-native-images.adoc @@ -0,0 +1,133 @@ +[[native-image.introducing-graalvm-native-images]] +== Introducing GraalVM Native Images +GraalVM Native Images provide a new way to deploy and run Java applications. +Compared to the Java Virtual Machine, native images can run with a smaller memory footprint and with much faster startup times. + +They are well suited to applications that are deployed using container images and are especially interesting when combined with "`Function as a service`" (FaaS) platforms. + +Unlike traditional applications written for the JVM, Graal Native Image applications require ahead-of-time processing in order to create an executable. +This ahead-of-time processing involves statically analyzing your application code from its main entry point. + +A GraalVM Native Image is a complete, platform-specific executable. +You do not need to ship a Java Virtual Machine in order to run a native image. + +TIP: If you just want to get started and experiment with GraalVM you can skip ahead to the "`<>`" section and return to this section later. + + + +[[native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments]] +=== Key Differences with JVM Deployments +The fact that GraalVM Native Images are produced ahead-of-time means that there are some key differences between native and JVM based applications. +The main differences are: + +* Static analysis of your application is performed at build-time from the `main` entry point. +* Code that cannot be reached when the native image is created will be removed and won't be part of the executable. +* GraalVM is not directly aware of dynamic elements of your code and must be told about reflection, resources, serialization, and dynamic proxies. +* The application classpath is fixed at build time and cannot change. +* There is no lazy class loading, everything shipped in the executables will be loaded in memory on startup. +* There are some limitations around some aspects of Java applications that are not fully supported. + +TIP: The {graal-native-image-docs}/Limitations/[Native Image Compatibility and Optimization Guide] section of the GraalVM reference documentation provide more details about GraalVM limitations. + + + +[[native-image.introducing-graalvm-native-images.understanding-aot-processing]] +=== Understanding Spring Ahead-of-Time Processing +Typical Spring Boot applications are quite dynamic and a lot of configuration is performed at at runtime. +In fact, the concept of Spring Boot auto-configuration depends heavily on reacting to the state of the runtime in order to configure things correctly. + +Although it would be possible to tell GraalVM about these dynamic aspects of the application, doing so would undo most of the benefit of static analysis. +So instead, when using Spring Boot to create native images, a closed-world is assumed and the dynamic aspects of the application are restricted. + +A closed-world assumption implies the following restrictions: + +* The classpath is fixed and fully defined at build time +* The beans defined in your application cannot change at runtime, meaning: + - The Spring `@Profile` annotation and profile-specific configuration is not supported + - Properties that change if a bean is created are not supported (for example, `@ConditionalOnProperty` and `.enable` properties). + +When these restrictions are in place, it becomes possible for Spring to perform ahead-of-time processing during build-time and generate additional assets that GraalVM can use. +A Spring AOT processed application will typically generate: + +* Java source code. +* Bytecode (for dynamic proxies etc). +* GraalVM JSON hint files: + - Resource hints (`resource-config.json`). + - Reflection hints (`reflect-config.json`). + - Serialization hints (`serialization-config.json`). + - Java Proxy Hints (`proxy-config.json`). + - JNI Hints (`jni-config.json`). + + + +[[native-image.introducing-graalvm-native-images.understanding-aot-processing.source-code-generation]] +==== Source Code Generation +Spring applications are composed of Spring Beans. +Internally, Spring Framework uses two distinct concepts to manage beans. +There are bean instances, which are the actual instances that have been created and can be injected into other beans. +There are also "`bean definitions`" which are used to define attributes of a bean and how its instance should be created. + +If we take a typical `@Configuration` class: + +include::code:MyConfiguration[] + +The "`bean definition`" is created by parsing the `@Configuration` class and finding the `@Bean` methods. +In the above example, we're defining a `BeanDefinition` for a singleton bean named "`myBean`". +We're also defining a `BeanDefinition` for the `MyConfiguration` class itself. + +When the `myBean` instance is required, Spring knows that it must invoke the `myBean()` method and use the result. +When running on the JVM, `@Configuration` class parsing happens when your application starts and `@Bean` methods are invoked using reflection. + +When creating a native image, Spring operates in a different way. +Rather than parsing `@Configuration` classes and generating bean definitions at runtime, it does it at build-time. +Once the bean definitions have been discovered, they are processed and converted into source code that can be ultimately analyzed by the GraalVM compiler. + +The Spring AOT process would convert the configuration class above to code like this: + +include::code:MyConfiguration__BeanDefinitions[] + +NOTE: The exact code generated may differ depending on the exact nature of your bean definitions. + +You can see above that the generated code creates equivalent bean definitions to the `@Configuration` class, but in a direct way that can be understood by GraalVM. + +There is a bean definition for the "`myConfiguration`" bean, and one for "`myBean`". +When a `myBean` instance is required, a `BeanInstanceSupplier` is called. +This supplier will invoke the `myBean()` method on the `myConfiguration` bean. + +NOTE: During Spring AOT processing your application is started up to the point that bean definitions are available. +Bean instances are not created during the AOT processing phase. + +Spring AOT will generate code like this for all your bean definitions. +It will also generate code when bean post-processing is required (for example, to call `@Autowired` methods). +An `ApplicationContextInitializer` will also be generated which will be used by Spring Boot to initialize the `ApplicationContext` when an AOT processed application is actually run. + +TIP: Although AOT generated source code can be verbose, it is quite readable and can be helpful to use when debugging an application. +Generated source files can be found in `target/spring-aot/main/sources` when using Maven and `build/generated/aotSources` with Gradle. + + + +[[native-image.introducing-graalvm-native-images.understanding-aot-processing.hint-file-generation]] +==== Hint File Generation +In addition to generating source files, Spring's AOT engine will also generate hint files that are used by GraalVM. +Hint files contain JSON data that describes how GraalVM should deal with things that it can't understand by directly inspecting the code. + +For example, you might be using a Spring annotation on a private method. +Spring will need to use reflection in order to invoke private methods, even on GraalVM. +When such situations arise, Spring can write a "`reflection hint`" so that GraalVM knows that even though the private method isn't called directly, it still needs to be available in the native image. + +Hint files are generated under `META-INF/native-image` where they are automatically picked up by GraalVM. + +TIP: Generated hint files can be found in `target/spring-aot/main/resources` when using Maven and `build/generated/aotResources` with Gradle. + + + +[[native-image.introducing-graalvm-native-images.understanding-aot-processing.proxy-class-generation]] +==== Proxy Class Generation +Spring sometimes needs to generate proxy classes to enhance the code you've written with additional features. +To do this, it uses the cglib library which directly generates bytecode. + +When an application is running on the JDK, proxy classes are generated dynamically as the application runs. +When creating a native image, these proxies need to be created at build-time so that they can be included by GraalVM. + +NOTE: Unlike source code generation, generated bytecode isn't particularly helpful when debugging an application. +However, if you need to inspect the contents of the `.class` files using a tool such as `javap` you can find them in `target/spring-aot/main/classes` for Maven and `build/generated/aotClasses` for Gradle. diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/testing-native-applications.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/testing-native-applications.adoc new file mode 100644 index 00000000000..8952799ee26 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/testing-native-applications.adoc @@ -0,0 +1,109 @@ +[[native-image.testing]] +== Testing GraalVM Native Images +When writing native image applications, we recommend that you continue to use the JVM whenever possible to develop the majority of your unit and integration tests. +This will help keep developer build times down and allow you to use existing IDE integrations. +With broad test coverage on the JVM, you can then focus native image testing on the areas that are likely to be different. + +For native image testing, you're generally looking to ensure that the following aspects work: + +* Spring's AOT engine is able to process your application and will it run in an AOT-processed mode. +* GraalVM has enough hints to ensure that a valid native image can be produced. + + + + +[[native-image.testing.with-the-jvm]] +=== Testing Ahead-of-time Processing With the JVM +When a Spring Boot application runs, it attempts to detect if it's running as a native image. +If it is running as a native image, it will initialize the application using the code that was generated during at build-time by Spring's AOT engine. + +If the application is running on a regular JVM, then any AOT generated code is ignored. + +Since the `native-image` compilation phase can take a while to complete, it's sometimes useful to run your application on the JVM but have it use the AOT generated initialization code. +Doing so helps you to quickly validate that there are no errors in the AOT generated code and nothing is missing when your application is eventually converted to a native image. + +To run a Spring Boot application on the JVM and have it use AOT generated code you can set the `spring.aot.enabled` system property to `true`. + +For example: + +[source,shell,indent=0,subs="verbatim"] +---- +$ java -Dspring.aot.enabled=true -jar myapplication.jar +---- + +NOTE: You need to ensure that the jar you're testing includes AOT generated code. +For Maven, this means that you should build with `-Pnative` to active the `native` profile. +For Gradle, you need to ensure that your build includes the `org.graalvm.buildtools.native` plugin. + +If your application starts with the `spring.aot.enabled` property set to `true`, then you have higher confidence that it will work when converted to a native image. + +You can also consider running integration tests against the running application. +For example, you could use Spring's `WebClient` to call your application REST endpoints. +Or you might consider using a project like Selenium to check your applications HTML responses. + + + +[[native-image.testing.with-native-build-tools]] +=== Testing With Native Build Tools +GraalVM's Native Build Tools includes the ability to run tests inside a native image. +This can be helpful when you want to deeply test that the internals of you application work in a GraalVM native image. + +Generating the native image that contains the tests to run can be a time consuming operation, so most developers will probably prefer to use the JVM locally. +They can, however, be very useful as part of a CI pipeline. +For example, you might choose to run native tests once a day as part of a "`nightly`" run. + +Spring Framework includes ahead-of-time support for running tests. +All the usual Spring testing features work with native image tests. +For example, you can continue to use the `@SpringBootTest` annotation. +You can also use Spring Boot's <> to test only specific parts of your application. + +Spring Framework's native testing support works in the following way: + +* Test are analyzed in order to discover any `ApplicationContext` instances that will be required. +* Spring's ahead-of-time processing is applied each to these application contexts and assets are generated. +* A native image is created, with the generated assets being processed by GraalVM. +* The native image also includes JUnit's `TestEngine` configured with a list of the discovered tests. +* The native image is started, triggering the engine which will run each test and report results. + + + +[[native-image.testing.with-native-build-tools.maven]] +==== Using Maven +To run native tests using Maven you should ensure that your `pom.xml` file uses the `spring-boot-starter-parent`. +You should have a `` section that looks like this: + +[source,xml,indent=0,subs="verbatim,attributes"] +---- + + org.springframework.boot + spring-boot-starter-parent + {spring-boot-version} + +---- + +The `spring-boot-starter-parent` declares a `nativeTest` profile that configures the executions that are needed to run the native tests. +You can activate profiles using the `-P` flag on the command line. + +TIP: If you don't want to use `spring-boot-starter-parent` you'll need to configure executions for the `process-test-aot` goal from Spring Boot's plugin and the `test` goal from the Native Build Tools plugin. + +To build the image and run the tests use the `test` goal with the `nativeTest` profile active: + +[indent=0,subs="verbatim"] +---- + $ mvn -PnativeTest test +---- + + + +[[native-image.testing.with-native-build-tools.gradle]] +==== Using Gradle +The Spring Boot Gradle plugin automatically configures AOT test tasks when the GraalVM Native Image plugin is applied. +You should check that your gradle build contains a `plugins` block that includes `org.graalvm.buildtools.native`. + +To run native tests using Gradle you can use the `nativeTest` task: + +[indent=0,subs="verbatim"] +---- + $ gradle nativeTest +---- + diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/whats-next.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/whats-next.adoc new file mode 100644 index 00000000000..cf100463d6c --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/native-image/whats-next.adoc @@ -0,0 +1,8 @@ +[[native-image.whats-next]] +== What to Read Next +If you want to learn more about the ahead-of-time processing provided by our build plugins, see the {spring-boot-maven-plugin-docs}[Maven] and {spring-boot-gradle-plugin-docs}[Gradle] plugin documentation. +To learn more about the APIs used to perform the processing, browse the `org.springframework.aot.generate` and `org.springframework.beans.factory.aot` packages of the Spring Framework sources. + +For known limitations with Spring and GraalVM, please see the {github-wiki}/Known-GraalVM-Native-Image-Limitations[Spring Boot wiki]. + +The next section goes on to cover the _<>_. diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyClass.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyClass.java new file mode 100644 index 00000000000..e96d0137420 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyClass.java @@ -0,0 +1,25 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.advanced.customhints; + +class MyClass { + + public void sayHello(String name) { + System.out.println("Hello " + name); + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyInterface.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyInterface.java new file mode 100644 index 00000000000..f71d050266b --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyInterface.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.advanced.customhints; + +/** + * @author Moritz Halbritter + */ +public interface MyInterface { + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyRuntimeHints.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyRuntimeHints.java new file mode 100644 index 00000000000..73f8f21fa3c --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MyRuntimeHints.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.advanced.customhints; + +import java.lang.reflect.Method; + +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.util.ReflectionUtils; + +public class MyRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + // Register method for reflection + Method method = ReflectionUtils.findMethod(MyClass.class, "sayHello", String.class); + hints.reflection().registerMethod(method, ExecutableMode.INVOKE); + + // Register resources + hints.resources().registerPattern("my-resource.txt"); + + // Register serialization + hints.serialization().registerType(MySerializableClass.class); + + // Register proxy + hints.proxies().registerJdkProxy(MyInterface.class); + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MySerializableClass.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MySerializableClass.java new file mode 100644 index 00000000000..a1bd0d0215e --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/MySerializableClass.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.advanced.customhints; + +import java.io.Serializable; + +class MySerializableClass implements Serializable { + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/testing/MyRuntimeHintsTests.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/testing/MyRuntimeHintsTests.java new file mode 100644 index 00000000000..8f92f44d90a --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/customhints/testing/MyRuntimeHintsTests.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.advanced.customhints.testing; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.boot.docs.nativeimage.advanced.customhints.MyRuntimeHints; + +import static org.assertj.core.api.Assertions.assertThat; + +class MyRuntimeHintsTests { + + @Test + void shouldRegisterHints() { + RuntimeHints hints = new RuntimeHints(); + new MyRuntimeHints().registerHints(hints, getClass().getClassLoader()); + assertThat(RuntimeHintsPredicates.resource().forResource("my-resource.txt")).accepts(hints); + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/nestedconfigurationproperties/MyProperties.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/nestedconfigurationproperties/MyProperties.java new file mode 100644 index 00000000000..f4d064e05ff --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/advanced/nestedconfigurationproperties/MyProperties.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.advanced.nestedconfigurationproperties; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; + +@ConfigurationProperties(prefix = "my.properties") +public class MyProperties { + + private String name; + + @NestedConfigurationProperty + private Nested nested = new Nested(); + + // @fold:on // getters / setters... + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public Nested getNested() { + return this.nested; + } + // @fold:off + + public static class Nested { + + private int number; + + // @fold:on // getters / setters... + public int getNumber() { + return this.number; + } + + public void setNumber(int number) { + this.number = number; + } + // @fold:off + + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/developingyourfirstapplication/sampleapplication/MyApplication.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/developingyourfirstapplication/sampleapplication/MyApplication.java new file mode 100644 index 00000000000..949576617fd --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/developingyourfirstapplication/sampleapplication/MyApplication.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.developingyourfirstapplication.sampleapplication; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@SpringBootApplication +public class MyApplication { + + @RequestMapping("/") + String home() { + return "Hello World!"; + } + + public static void main(String[] args) { + SpringApplication.run(MyApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyBean.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyBean.java new file mode 100644 index 00000000000..08de0b3b398 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyBean.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.introducinggraalvmnativeimages.understandingaotprocessing.sourcecodegeneration; + +public class MyBean { + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration.java new file mode 100644 index 00000000000..8ebf93729a0 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration.java @@ -0,0 +1,30 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.nativeimage.introducinggraalvmnativeimages.understandingaotprocessing.sourcecodegeneration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class MyConfiguration { + + @Bean + public MyBean myBean() { + return new MyBean(); + } + +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration__BeanDefinitions.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration__BeanDefinitions.java new file mode 100644 index 00000000000..1fd27531022 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration__BeanDefinitions.java @@ -0,0 +1,41 @@ +package org.springframework.boot.docs.nativeimage.introducinggraalvmnativeimages.understandingaotprocessing.sourcecodegeneration; + +import org.springframework.beans.factory.aot.BeanInstanceSupplier; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.RootBeanDefinition; + +/** + * Bean definitions for {@link MyConfiguration} + */ +@SuppressWarnings("javadoc") +public class MyConfiguration__BeanDefinitions { + + /** + * Get the bean definition for 'myConfiguration' + */ + public static BeanDefinition getMyConfigurationBeanDefinition() { + Class beanType = MyConfiguration.class; + RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType); + beanDefinition.setInstanceSupplier(MyConfiguration::new); + return beanDefinition; + } + + /** + * Get the bean instance supplier for 'myBean'. + */ + private static BeanInstanceSupplier getMyBeanInstanceSupplier() { + return BeanInstanceSupplier.forFactoryMethod(MyConfiguration.class, "myBean").withGenerator( + (registeredBean) -> registeredBean.getBeanFactory().getBean(MyConfiguration.class).myBean()); + } + + /** + * Get the bean definition for 'myBean' + */ + public static BeanDefinition getMyBeanBeanDefinition() { + Class beanType = MyBean.class; + RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType); + beanDefinition.setInstanceSupplier(getMyBeanInstanceSupplier()); + return beanDefinition; + } + +} \ No newline at end of file