Polish native image documentation

See gh-32582
This commit is contained in:
Scott Frederick 2022-10-20 11:45:10 -05:00
parent 010891a3c6
commit bdedae21c0
5 changed files with 54 additions and 54 deletions

View File

@ -40,7 +40,7 @@ You can also deploy Spring Boot applications to any servlet 5.0+ compatible cont
[[getting-started.system-requirements.graal]]
=== GraalVM Native Images
Spring Boot applications can be <<native-image#native-image.introducing-graalvm-native-images,converted into a Native Image>> using using Graal {graal-version} or above.
Spring Boot applications can be <<native-image#native-image.introducing-graalvm-native-images,converted into a Native Image>> using using GraalVM {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].

View File

@ -5,7 +5,7 @@
[[native-image.advanced.nested-configuration-properties]]
=== Nested Configuration Properties
Reflection hints are automatically created for configuration properties by Spring's ahead-of-time engine.
Reflection hints are automatically created for configuration properties by the Spring 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[]
@ -13,28 +13,28 @@ 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.
NOTE: Please use public getters and setters, otherwise the properties will not be bindable.
[[native-image.advanced.converting-executable-jars]]
=== Converting a Spring Boot Executable JAR
It is possible to convert a Spring Boot <<executable-jar#appendix.executable-jar, executable JAR>> into a native image as long at the jar contains the AOT generated assets.
=== Converting a Spring Boot Executable Jar
It is possible to convert a Spring Boot <<executable-jar#appendix.executable-jar, executable jar>> 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.
* You can keep 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.
You can convert a Spring Boot executable jar into a native image using Cloud Native Buildpacks, or using 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.
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.
Spring Boot applications usually use Cloud Native 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).
@ -42,7 +42,7 @@ https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non
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:
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"]
----
@ -65,11 +65,11 @@ Once `pack` has finished, you can launch the application using `docker run`:
[[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.
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:
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"]
----
@ -86,7 +86,7 @@ NOTE: These commands work on Linux or MacOS machines, you will need to adapt the
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.
WARNING: The `native-image` `-cp` flag does not accept wildcards.
You need to ensure that all jars are listed (the command above uses `find` and `tr` to do this).

View File

@ -1,10 +1,10 @@
[[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.
Now that we have a good overview of GraalVM Native Images and how the Spring ahead-of-time engine works, we can look at how to create an application.
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 Spring Boot support for Cloud Native Buildpacks 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.
@ -32,8 +32,8 @@ This means you can just type a single command and quickly get a sensible image i
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.
NOTE: The builder used for the images is `paketobuildpacks/builder:tiny`.
It has small footprint and reduced surface attack, but you can also use `paketobuildpacks/builder:base` or `paketobuildpacks/builder:full` to have more tools available in the image if required.
@ -99,7 +99,7 @@ You can run the task using:
[[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.
Once you have run the appropriate build command, a Docker image should be available.
You can start your application using `docker run`:
[source,shell,indent=0,subs="verbatim"]
@ -201,7 +201,7 @@ 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.
When the Native Build Tools Gradle plugin is applied to your project, the Spring Boot Gradle plugin will automatically trigger the Spring 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"]

View File

@ -3,9 +3,9 @@
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.
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.
Unlike traditional applications written for the JVM, GraalVM 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.
@ -33,7 +33,7 @@ TIP: The {graal-native-image-docs}/Limitations/[Native Image Compatibility and O
[[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.
Typical Spring Boot applications are quite dynamic and configuration is performed 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.
@ -49,14 +49,14 @@ A closed-world assumption implies the following restrictions:
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).
* 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`).
- 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`)
@ -65,32 +65,32 @@ A Spring AOT processed application will typically generate:
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.
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.
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 creating 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.
Once the bean definitions have been discovered, they are processed and converted into source code that can be 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.
NOTE: The exact code generated may differ depending on the 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`".
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.
@ -101,19 +101,19 @@ 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.
TIP: Although AOT generated source code can be verbose, it is quite readable and can be helpful 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.
In addition to generating source files, the Spring 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.
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.

View File

@ -6,7 +6,7 @@ With broad test coverage on the JVM, you can then focus native image testing on
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.
* The Spring 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.
@ -14,8 +14,8 @@ For native image testing, you're generally looking to ensure that the following
[[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.
When a Spring Boot application runs, it attempts to detect if it is 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 the Spring AOT engine.
If the application is running on a regular JVM, then any AOT generated code is ignored.
@ -31,45 +31,45 @@ For example:
$ java -Dspring.aot.enabled=true -jar myapplication.jar
----
NOTE: You need to ensure that the jar you're testing includes AOT generated code.
NOTE: You need to ensure that the jar you are 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.
For example, you could use the Spring `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.
GraalVM 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.
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.
For example, you might choose to run native tests once a day.
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 <<features#features.testing.spring-boot-applications.autoconfigured-tests, "`test slices`">> to test only specific parts of your application.
You can also use Spring Boot <<features#features.testing.spring-boot-applications.autoconfigured-tests, test slices>> 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.
* Ahead-of-time processing is applied to each of 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 also includes the JUnit `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`.
To run native tests using Maven, ensure that your `pom.xml` file uses the `spring-boot-starter-parent`.
You should have a `<parent>` section that looks like this:
[source,xml,indent=0,subs="verbatim,attributes"]
@ -84,9 +84,9 @@ You should have a `<parent>` section that looks like this:
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.
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 the Spring Boot 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:
To build the image and run the tests, use the `test` goal with the `nativeTest` profile active:
[indent=0,subs="verbatim"]
----