parent
010891a3c6
commit
bdedae21c0
|
@ -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].
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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"]
|
||||
----
|
||||
|
|
Loading…
Reference in New Issue