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