|
| 1 | +[[native-image.advanced]] |
| 2 | +== Advanced Native Images Topics |
| 3 | + |
| 4 | + |
| 5 | + |
| 6 | +[[native-image.advanced.nested-configuration-properties]] |
| 7 | +=== Nested Configuration Properties |
| 8 | +Reflection hints are automatically created for configuration properties by Spring's ahead-of-time engine. |
| 9 | +Nested configuration properties, however, *must* be annotated with `@NestedConfigurationProperty`, otherwise they won't be detected and will not be bindable. |
| 10 | + |
| 11 | +include::code:MyProperties[] |
| 12 | + |
| 13 | +The example above produces configuration properties for `my.properties.name` and `my.properties.nested.number`. |
| 14 | +Without the `@NestedConfigurationProperty` annotation on the `nested` field, the `my.properties.nested.number` property would not be bindable in a native image. |
| 15 | + |
| 16 | +NOTE: Please use public getters / setters, otherwise the properties won't be bindable. |
| 17 | + |
| 18 | + |
| 19 | + |
| 20 | +[[native-image.advanced.converting-executable-jars]] |
| 21 | +=== Converting a Spring Boot Executable JAR |
| 22 | +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. |
| 23 | +This can be useful for a number of reasons, including: |
| 24 | + |
| 25 | +* You can keeping your regular JVM pipeline and turn the JVM application into a native image on your CI/CD platform. |
| 26 | +* 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. |
| 27 | + |
| 28 | +You can convert a Spring Boot executable jar into a native image using buildpacks, or the `native-image` tool that is shipped with GraalVM. |
| 29 | + |
| 30 | +NOTE: Your executable JAR must include AOT generated assets such as generated classes and JSON hint files. |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +[[native-image.advanced.converting-executable-jars.buildpacks]] |
| 35 | +==== Using Buildpacks |
| 36 | +Spring Boot applications usually use Buildpacks via the Maven (`mvn spring-boot:build-image`), or Gradle (`gradle bootBuildImage`) integrations. |
| 37 | +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. |
| 38 | + |
| 39 | + |
| 40 | +First, make sure that a Docker daemon is available (see https://docs.docker.com/installation/#installation[Get Docker] for more details). |
| 41 | +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. |
| 42 | + |
| 43 | +You also need to install `pack` by following https://buildpacks.io//docs/tools/pack/#install[the installation guide on buildpacks.io]. |
| 44 | + |
| 45 | +Assuming an AOT processed Spring Boot executable JAR built as `myproject-0.0.1-SNAPSHOT.jar` is in the `target` directory, run: |
| 46 | + |
| 47 | +[source,shell,indent=0,subs="verbatim"] |
| 48 | +---- |
| 49 | + $ pack build --builder paketobuildpacks/builder:tiny \ |
| 50 | + --path target/myproject-0.0.1-SNAPSHOT.jar \ |
| 51 | + --env 'BP_NATIVE_IMAGE=true' \ |
| 52 | + my-application:0.0.1-SNAPSHOT |
| 53 | +---- |
| 54 | + |
| 55 | +NOTE: You do not need to have a local GraalVM installation to generate an image in this way. |
| 56 | + |
| 57 | +Once `pack` has finished, you can launch the application using `docker run`: |
| 58 | + |
| 59 | +[source,shell,indent=0,subs="verbatim"] |
| 60 | +---- |
| 61 | + $ docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT |
| 62 | +---- |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +[[native-image.advanced.converting-executable-jars.native-image]] |
| 67 | +==== Using GraalVM native-image |
| 68 | +Another option to turn an AOT processed Spring Boot executable JAR into a native executable is to use the GraalVM `native-image` tool. |
| 69 | +For this to work, you'll need a GraalVM distribution on your machine. |
| 70 | +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!. |
| 71 | + |
| 72 | +Assuming an AOT processed Spring Boot executable JAR built as `myproject-0.0.1-SNAPSHOT.jar` is in the `target` directory, run: |
| 73 | + |
| 74 | +[source,shell,indent=0,subs="verbatim"] |
| 75 | +---- |
| 76 | + $ rm -rf target/native |
| 77 | + $ mkdir -p target/native |
| 78 | + $ cd target/native |
| 79 | + $ jar -xvf ../myproject-0.0.1-SNAPSHOT.jar |
| 80 | + $ native-image -H:Name=myproject @META-INF/native-image/argfile -cp .:BOOT-INF/classes:`find BOOT-INF/lib | tr '\n' ':'` |
| 81 | + $ mv myproject ../ |
| 82 | +---- |
| 83 | + |
| 84 | +NOTE: These commands work on Linux or MacOS machines, you will need to adapt them for Windows. |
| 85 | + |
| 86 | +TIP: The `@META-INF/native-image/argfile` might not be packaged in your jar. |
| 87 | +It is only included when reachability metadata overrides are needed. |
| 88 | + |
| 89 | +WARNING: The `native-image` `-cp` flag does not not accept wildcards. |
| 90 | +You need to ensure that all jars are listed (the command above uses `find` and `tr` to do this). |
| 91 | + |
| 92 | + |
| 93 | + |
| 94 | +[[native-image.advanced.using-the-tracing-agent]] |
| 95 | +=== Using the Tracing Agent |
| 96 | +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. |
| 97 | +Spring should generate most of these hints automatically, but the tracing agent can be used to quickly identify the missing entries. |
| 98 | + |
| 99 | +When using the agent to generate hints for a native image, there are a couple of approaches: |
| 100 | + |
| 101 | +* Launch the application directly and exercise it. |
| 102 | +* Run application tests to exercise the application. |
| 103 | + |
| 104 | +The first option is interesting for identifying the missing hints when a library or a pattern is not recognized by Spring. |
| 105 | + |
| 106 | +The second option sounds more appealing for a repeatable setup, but by default the generated hints will include anything required by the test infrastructure. |
| 107 | +Some of these will be unnecessary when the application runs for real. |
| 108 | +To address this problem the agent supports an access-filter file that will cause certain data to be excluded from the generated output. |
| 109 | + |
| 110 | + |
| 111 | + |
| 112 | +[[native-image.advanced.using-the-tracing-agent.launch]] |
| 113 | +==== Launch the Application Directly |
| 114 | +Use the following command to launch the application with the native image tracing agent attached: |
| 115 | + |
| 116 | +[source,shell,indent=0,subs="verbatim,attributes"] |
| 117 | +---- |
| 118 | + $ java -Dspring.aot.enabled=true \ |
| 119 | + -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/ \ |
| 120 | + -jar target/myproject-0.0.1-SNAPSHOT.jar |
| 121 | +---- |
| 122 | + |
| 123 | +Now you can exercise the code paths you want to have hints for and then stop the application with `ctrl-c`. |
| 124 | + |
| 125 | +On application shutdown the native image tracing agent will write the hint files to the given config output directory. |
| 126 | +You can either manually inspect these files, or use them as input to the native image build process. |
| 127 | +To use them as input, copy them into the `src/main/resources/META-INF/native-image/` directory. |
| 128 | +The next time you build the native image, GraalVM will take these files into consideration. |
| 129 | + |
| 130 | +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. |
| 131 | +For further reading, please see https://www.graalvm.org/reference-manual/native-image/Agent/[the official documentation]. |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +[[native-image.advanced.custom-hints]] |
| 136 | +=== Custom Hints |
| 137 | +If you need to provide your own hints for reflection, resources, serialization, proxy usage etc. you can use the `RuntimeHintsRegistrar` API. |
| 138 | +Create a class that implements the `RuntimeHintsRegistrar` interface, then make appropriate calls to the provided `RuntimeHints` instance: |
| 139 | + |
| 140 | +include::code:MyRuntimeHints[] |
| 141 | + |
| 142 | +You can then use `@ImportRuntimeHints` on any `@Configuration` class (for example your `@SpringBootApplication` annotated application class) to activate those hints. |
| 143 | + |
| 144 | + |
| 145 | + |
| 146 | +[[native-image.advanced.custom-hints.testing]] |
| 147 | +==== Testing custom hints |
| 148 | +The `RuntimeHintsPredicates` API can be used to test your hints. |
| 149 | +The API provides methods that build a `Predicate` that can be used to test a `RuntimeHints` instance. |
| 150 | + |
| 151 | +If you're using AssertJ, your test would look like this: |
| 152 | + |
| 153 | +include::code:MyRuntimeHintsTests[] |
| 154 | + |
| 155 | + |
| 156 | + |
| 157 | +[[native-image.advanced.known-limitations]] |
| 158 | +=== Known Limitations |
| 159 | +GraalVM native images are an evolving technology and not all libraries provide support. |
| 160 | +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. |
| 161 | +Spring itself doesn't contain hints for 3rd party libraries and instead relies on the reachability metadata project. |
| 162 | + |
| 163 | +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. |
| 164 | +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. |
| 165 | + |
| 166 | +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]. |
0 commit comments