plugins {
id 'io.micronaut.application' version '3.4.1'
}
Micronaut Gradle plugin
Version 3.4.1
1. What’s new
Note
|
Documentation for the 2.x branch can be found here. |
The 3.0.0 version of the plugin integrates with the official GraalVM plugin which introduces some breaking changes:
-
the
nativeImage
task is now replaced withnativeCompile
-
native image configuration happens in the
graalvmNative
DSL block -
The GraalVM SDK being used depends on how you configure toolchains
Please refer to the native image section for more help: the toolchain selection mechanism might be surprising to you.
2. The Gradle plugins
A Gradle Plugin which makes development of Micronaut application and libraries a breeze.
This project currently consists of different plugins:
-
the
io.micronaut.application
plugin is aimed at building Micronaut applications. It automatically integrates with GraalVM by applying theio.micronaut.graalvm
plugin transparently. -
the
io.micronaut.library
plugin is aimed at building Micronaut libraries. -
the
io.micronaut.graalvm
plugin integrates with the official GraalVM Native Build Tools plugin and configures it for Micronaut applications. -
the
io.micronaut.aot
plugin integrates with Micronaut AOT to produce optimized binaries.
2.1. Individual plugins
In addition to the library and application plugins described in the following documentation, you can apply one of the following plugins to your project.
For example, the minimal
plugins can be used to reduce the number of tasks, for example if you don’t need Docker or GraalVM support:
Plugin id | Description | Also applies |
---|---|---|
Allows building Micronaut libraries, without GraalVM support |
|
|
Allows building Micronaut applications, without GraalVM nor Docker support |
|
|
Adds support for building native images |
||
Adds support for building Docker images |
||
Adds support for Micronaut AOT |
||
A typical Micronaut Library, with support for GraalVM |
|
|
A typical Micronaut Application, with support for GraalVM and Docker |
|
Using the io.micronaut.application
plugin:
plugins {
id("io.micronaut.application") version "3.4.1"
}
is therefore equivalent to applying those plugins individually:
plugins {
id 'io.micronaut.minimal.application' version '3.4.1'
id 'io.micronaut.docker' version '3.4.1'
id 'io.micronaut.graalvm' version '3.4.1'
}
apply plugin: com.diffplug.gradle.eclipse.apt.AptEclipsePlugin
plugins {
id("io.micronaut.application") version "3.4.1"
id("io.micronaut.docker") version "3.4.1"
id("io.micronaut.graalvm") version "3.4.1"
}
apply(plugin=com.diffplug.gradle.eclipse.apt.AptEclipsePlugin::class.java)
io.micronaut.minimal.application
, io.micronaut.graalvm
and io.micronaut.docker
plugins (as well as the Eclipse annotation processing support plugin).
3. Quick Start
Template projects are available via Micronaut Launch for each language.
To get started you can use the Micronaut CLI:
$ mn create-app demo --lang java
$ mn create-app demo --lang groovy
$ mn create-app demo --lang kotlin
Or if you don’t have it installed via curl
:
# for Java
$ curl https://launch.micronaut.io/demo.zip?lang=java \
-o demo.zip && unzip demo.zip -d demo && cd demo
# for Groovy
$ curl https://launch.micronaut.io/demo.zip?lang=groovy \
-o demo.zip && unzip demo.zip -d demo && cd demo
# for Kotlin
$ curl https://launch.micronaut.io/demo.zip?lang=kotlin \
-o demo.zip && unzip demo.zip -d demo && cd demo
4. Micronaut Library Plugin
plugins {
id 'io.micronaut.library' version '3.4.1'
}
plugins {
id("io.micronaut.library") version "3.4.1"
}
The Micronaut library plugin applies the following modifications to the build:
-
Applies the Micronaut Bill of Materials (BOM)
-
Applies the
java-library
plugin -
Configures annotation processing for the current language (Groovy, Java or Kotlin)
The micronaut
DSL can be used to configure how this behaves.
The minimum requirement is to set the Micronaut version to use. This can be done by setting micronautVersion
in gradle.properties
or as follows in build.gradle(.kts)
:
micronaut {
version "3.1.1"
}
micronaut {
version.set("3.1.1")
}
Complete example with the default settings:
micronaut {
version "3.1.1"
processing {
// Sets whether incremental annotation processing is enabled
incremental true
// Sets the module name.
// This should be the same as the artifactId in the POM
module project.name
// Sets the group.
// This should be th same as the groupId in the POM
group project.group
// Sets the Java package names containing any custom Micronaut
// meta annotations (new annotations annotated with say @Around).
// Generally used only for advanced cases such as defining new AOP
// advice. If omitted however, incremental annotation processing
// will not work correctly
annotations "com.example.*"
// additional sourceSets can be configured here to apply the BOM
// and annotation processors to source sets other than 'main'
sourceSets(
sourceSets.main
)
}
}
micronaut {
version.set("3.1.1")
processing {
// Sets whether incremental annotation processing is enabled
incremental.set(true)
// Sets the module name.
// This should be the same as the artifactId in the POM
module.set(project.name)
// Sets the group.
// This should be th same as the groupId in the POM
group.set(project.group)
// Sets the Java package names containing any custom Micronaut
// meta annotations (new annotations annotated with say @Around).
// Generally used only for advanced cases such as defining new AOP
// advice. If omitted however, incremental annotation processing
// will not work correctly
annotations.add("com.example.*")
// additional sourceSets can be configured here to apply the BOM
// and annotation processors to source sets other than 'main'
sourceSets(
sourceSets.findByName("main")
)
}
}
Note
|
The Micronaut Library plugin also supports Groovy and Kotlin sources. |
4.1. Kotlin Support
For Kotlin, the Kotlin jvm
and kapt
plugins must be configured:
plugins {
id "org.jetbrains.kotlin.jvm" version "1.5.30"
id "org.jetbrains.kotlin.kapt" version "1.5.30"
id "io.micronaut.library" version "3.4.1"
}
plugins {
id("org.jetbrains.kotlin.jvm") version "1.5.30"
id("org.jetbrains.kotlin.kapt") version "1.5.30"
id("io.micronaut.library") version "3.4.1"
}
4.2. Minimal Build
With the io.micronaut.library
plugin applied a minimal build to get started writing a library for Micronaut that written in Java and is tested with JUnit 5 looks like:
plugins {
id 'io.micronaut.library' version '3.4.1'
}
version "0.1"
group "com.example"
repositories {
mavenCentral()
}
micronaut {
version = "3.1.1"
}
dependencies {
testImplementation("io.micronaut.test:micronaut-test-junit5")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
plugins {
id("io.micronaut.library") version "3.4.1"
}
version = "0.1"
group = "com.example"
repositories {
mavenCentral()
}
micronaut {
version.set("3.1.1")
}
dependencies {
testImplementation("io.micronaut.test:micronaut-test-junit5")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
5. Micronaut Application Plugin
plugins {
id "io.micronaut.application" version "3.4.1"
}
plugins {
id("io.micronaut.application") version "3.4.1"
}
The Micronaut application plugin extends the Micronaut Library plugin and adds the following customizations:
-
Instead of the
java-library
plugin the plugin applies the Gradleapplication
plugin -
Applies the
io.micronaut.graalvm
plugin -
Correctly configures Gradle for continuous build
The following additional tasks are provided by this plugin:
-
buildLayers
- Builds application layers for use in a Docker container -
dockerfile
- Builds a Docker File for a Micronaut application -
dockerBuild
- Builds a Docker Image using the Docker Gradle plugin -
dockerfileNative
- Builds a Docker File for for GraalVM Native Image -
dockerBuildNative
- Builds a Native Docker Image using GraalVM Native Image -
nativeCompile
- Builds a GraalVM Native Image -
testNativeImage
(since 1.1.0) - Builds a GraalVM Native Image, starts the native server and runs tests against the server -
dockerPush
- Pushes a Docker Image to configured container registry -
dockerPushNative
- Pushes a Docker Image built with GraalVM Native Image to configured container registry
To run an application with continuous build use the run
task with the -t
parameter:
$ ./gradlew run -t
5.1. Minimal Build
With the io.micronaut.application
plugin applied a minimal build to get started with a Micronaut server application that is written in Java and tested with JUnit 5 looks like:
plugins {
id 'io.micronaut.application' version '3.4.1'
}
version "0.1"
group "com.example"
repositories {
mavenCentral()
}
micronaut {
version = "3.1.1"
}
dependencies {
implementation("io.micronaut:micronaut-http-server-netty")
runtimeOnly("ch.qos.logback:logback-classic")
testImplementation("io.micronaut.test:micronaut-test-junit5")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
application {
mainClass = "example.Application"
}
plugins {
id("io.micronaut.application") version "3.4.1"
}
version = "0.1"
group = "com.example"
repositories {
mavenCentral()
}
micronaut {
version.set("3.1.1")
}
dependencies {
implementation("io.micronaut:micronaut-http-server-netty")
runtimeOnly("ch.qos.logback:logback-classic")
testImplementation("io.micronaut.test:micronaut-test-junit5")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
application {
mainClass.set("example.Application")
}
5.2. Kotlin Support
The most simple Kotlin build using a build.gradle(.kts)
file looks like:
plugins {
id "org.jetbrains.kotlin.jvm" version "1.5.30"
id "org.jetbrains.kotlin.kapt" version "1.5.30"
id "org.jetbrains.kotlin.plugin.allopen" version "1.5.30"
id "io.micronaut.application" version "3.4.1"
}
version "0.1"
group "com.example"
repositories {
mavenCentral()
}
micronaut {
version = "3.1.1"
}
dependencies {
implementation "io.micronaut:micronaut-http-server-netty"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30"
implementation "org.jetbrains.kotlin:kotlin-reflect:1.5.30")
runtimeOnly "ch.qos.logback:logback-classic")
testImplementation("io.micronaut.test:micronaut-test-junit5")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
application {
mainClass = "example.ApplicationKt"
}
plugins {
id("org.jetbrains.kotlin.jvm") version "1.5.30"
id("org.jetbrains.kotlin.kapt") version "1.5.30"
id("org.jetbrains.kotlin.plugin.allopen") version "1.5.30"
id("io.micronaut.application") version "3.4.1"
}
version = "0.1"
group = "com.example"
repositories {
mavenCentral()
}
micronaut {
version.set("3.1.1")
}
dependencies {
implementation("io.micronaut:micronaut-http-server-netty")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.5.30")
runtimeOnly("ch.qos.logback:logback-classic")
testImplementation("io.micronaut.test:micronaut-test-junit5")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
application {
mainClass.set("example.ApplicationKt")
}
5.3. GraalVM Native Image
Since version 3.0.0, the Micronaut plugins rely on the official GraalVM plugin to build native images.
Those plugins make use of the Gradle toolchains support, which means that the SDK which is used to build the native is decorrelated from the JVM which is used to launch Gradle itself. Said differently, you can run Gradle with OpenJDK, while still building native images using the GraalVM SDK.
The Micronaut Gradle plugin will automatically configure the toolchains support for you, but there are a few things that you should be aware of:
-
running Gradle with a GraalVM SDK doesn’t necessarily imply that Gradle will use the same SDK to build native images
-
Gradle will try to locate a compatible GraalVM toolchain to build images. You can tweak what GraalVM version to use by following the official documentation.
Important
|
While the toolchain selection will properly select a GraalVM SDK which matches your language version requirements, it will not let you pick a particular GraalVM version (say, prefer 21.3 over 21.1). If your application depends on a specific GraalVM version, you will have to disable automatic detection like explained below. |
If you have several GraalVM installations available, or that you want to disable the automatic toolchain recognition, we recommend that you do the following:
-
setup an environment variable named
GRAALVM_HOME
pointing to your GraalVM installation -
edit your
gradle.properties
file to add the following options:
# Disable Gradle automatic download of Java SDKs
org.gradle.java.installations.auto-download=false
# Disable auto-detection of Java installations
org.gradle.java.installations.auto-detect=false
# Setup explicitly that the Java version to use
# should be the one from the JAVA_HOME environment variable
org.gradle.java.installations.fromEnv=JAVA_HOME
Alternatively you can pass those options from the command line:
./gradlew -Porg.gradle.java.installations.auto-download=false \
-Porg.gradle.java.installations.auto-detect=false \
-Porg.gradle.java.installations.fromEnv=JAVA_HOME \
build
You can build a native image by running the following task:
$ ./gradlew nativeCompile
And you can run it by calling the following task:
$ ./gradlew nativeRun
You can tweak the native image options by configuring the graalvmNative
extension as explained in the plugin documentation.
For example you can add options to the main image by doing:
graalvmNative {
binaries {
main {
buildArgs << "-H:-DeleteLocalSymbols"
buildArgs << "-H:+PreserveFramePointer"
}
}
}
graalvmNative {
binaries {
named("main") {
buildArgs.add("-H:-DeleteLocalSymbols")
buildArgs.add("-H:+PreserveFramePointer")
}
}
}
Important
|
If you update an existing Micronaut application that contains the file src/main/resources/META-INF/native-image/xxxxx/native-image.properties , please make sure to delete the properties -H:Name and -H:Class from the file because they are managed automatically by the plugin.
|
5.3.1. Build "mostly static" native images
Since GraalVM 21.0 it is possible to create "mostly static" native images that can run in a distroless docker image. You only need to configure the appropriate baseImage and the plugin will automatically configure GraalVM:
tasks.named('dockerfileNative') {
baseImage('gcr.io/distroless/cc-debian10')
}
tasks.named<io.micronaut.gradle.docker.NativeImageDockerfile>("dockerfileNative") {
baseImage("gcr.io/distroless/cc-debian10")
}
In case you want to use another base image you need to set the appropriate GraalVM flag:
tasks.named('dockerfileNative') {
baseImage(...)
args('-H:+StaticExecutableWithDynamicLibC')
}
tasks.named<io.micronaut.gradle.docker.NativeImageDockerfile>("dockerfileNative") {
baseImage(...)
args("-H:+StaticExecutableWithDynamicLibC")
}
5.4. Testing Native Images
Note
|
This feature is independent from the official GraalVM testing support, which actually runs a test suite within a native image. Micronaut native test support launches a JVM test suite against a native image server. |
Since 1.1.x of the plugin, you can also use the testNativeImage
task to start the Micronaut native server and run tests against it.
Important
|
This feature only works in combination with micronaut-test-core versions 2.2.1 or above. Make sure your test classpath includes at least this version of Micronaut Test.
|
Using this task will replace the regular embedded server used for tests with the natively built executable:
./gradlew testNativeImage
It is important to note that there are some limitations to this approach in that the native server is no longer "embedded" in the test. This has the following implications:
-
It is not possible to mock components using
@MockBean
or replace beans using@Replaces
since the native server starts in a separate process and beans injected into or defined by the test are no longer shared with the application under test since it is running in a separate process. -
The native server starts with the
test
environment active, however the classpath of the application is the runtime classpath not the test classpath. This has the implication that certain testing features (like for example Testcontainers' usage of JDBC URLs to start containers) won’t work and you have to explicitly start any test containers in the test itself.
If you wish to split your native image tests from your regular tests you can create an additional source set for integration tests and the plugin will add an additional task suffixed with *NativeImage
to run the native image tests, for example: gradle integrationTestNativeImage
.
5.5. Docker Support
The Micronaut plugin includes integration with the Gradle Docker plugin allowing you to easily build applications and native images using Docker containers.
Applications are built as layered JARs using the buildLayers
task ensuring optimized Docker images for Java applications.
To build a regular Java application into a Docker container that is ready to be deployed and exposes ports 8080
you can simply do:
$ ./gradlew dockerBuild
The default uses an openjdk:17-alpine
base image, however you can easily switch the base image to use by using the baseImage
property of the dockerfile
task:
tasks.named("dockerfile") {
baseImage = "oracle/graalvm-ce:20.3.0-java11"
}
tasks.named<MicronautDockerfile>("dockerfile") {
baseImage.set("oracle/graalvm-ce:20.3.0-java11")
}
The above examples switches to use GraalVM CE 20.3.0 as a base image.
To build the application into a Native Image you can run:
$ ./gradlew dockerBuildNative
Note that for this to work you must build the application with the same GraalVM SDK as used to build the image.
To push the container to the currently configured container registry you can use either dockerPush
or dockerPushNative
for the native image:
$ ./gradlew dockerPush
To configure the image names to push you can use the images
setting of the dockerBuild
task.
For example the following configures dockerPush
to use Oracle Container Registry:
tasks.named("dockerBuild") {
images = ["eu-frankfurt-1.ocir.io/xyzzyz/repo/my-image:$project.version"]
}
tasks.named("dockerBuildNative") {
images = ["eu-frankfurt-1.ocir.io/xyzzyz/repo/my-image-native:$project.version"]
}
tasks.named<DockerBuildImage>("dockerBuild") {
images.add("eu-frankfurt-1.ocir.io/xyzzyz/repo/my-image:$project.version")
}
tasks.named<DockerBuildImage>("dockerBuildNative") {
images.add("eu-frankfurt-1.ocir.io/xyzzyz/repo/my-image-native:$project.version")
}
Notice that you can supply two different image names to push to for the JVM version and the native version of the application.
If you wish to customize the docker builds that are used, the easiest way is to run ./gradlew dockerfile
(or dockerfileNative
for the native version) and copy the generated Dockerfile
from build/docker
to your root directory and modify as required.
If you wish to customize the JVM arguments or native image arguments then it is possible to do so with the args
method of the dockerfile
and dockerfileNative
tasks:
tasks.named("dockerfile") {
args("-Xmx128m")
}
tasks.named("dockerfileNative") {
args("-Xmx64m")
}
tasks.named<MicronautDockerfile>("dockerfile") {
args("-Xmx128m")
}
tasks.named<io.micronaut.gradle.docker.NativeImageDockerfile>("dockerfileNative") {
args("-Xmx64m")
}
The above configuration uses a max heap setting of 128m
for Java and 64m
for native image for the application.
To add additional docker instructions to the generated Dockerfile, such as adding a HEALTHCHECK, you can do the following. The additional instructions will be added at the end of the Dockerfile
just before the ENTRYPOINT
.
tasks.named("dockerfile") {
args("-Xmx128m")
instruction """HEALTHCHECK CMD curl -s localhost:8090/health | grep '"status":"UP"' """
}
tasks.named("dockerfileNative") {
args("-Xmx64m")
instruction """HEALTHCHECK CMD curl -s localhost:8090/health | grep '"status":"UP"'"""
}
tasks.named<Dockerfile>("dockerfile") {
args("-Xmx128m")
instruction("""HEALTHCHECK CMD curl -s localhost:8090/health | grep '"status":"UP"' """)
}
tasks.named<io.micronaut.gradle.docker.NativeImageDockerfile>("dockerfileNative") {
args("-Xmx64m")
instruction("""HEALTHCHECK CMD curl -s localhost:8090/health | grep '"status":"UP"'""")
}
You can also add any of the other instructions/commands that the docker plugin supports, see the Dockerfile task documentation.
5.6. Micronaut Runtimes
A higher level concept of "runtimes" is included in the Micronaut Gradle plugin which essentially allows the plugin to decide which server runtime to include in the dependencies of the application when building the application. For example consider this minimal build:
plugins {
id 'io.micronaut.application' version '3.4.1'
}
version "0.1"
group "com.example"
repositories {
mavenCentral()
}
micronaut {
version = "3.1.1"
runtime "netty"
}
dependencies {
runtimeOnly("ch.qos.logback:logback-classic")
}
application {
mainClass = "example.Application"
}
plugins {
id("io.micronaut.application") version "3.4.1"
}
version = "0.1"
group = "com.example"
repositories {
mavenCentral()
}
micronaut {
version.set("3.1.1")
runtime.set("netty")
}
dependencies {
runtimeOnly("ch.qos.logback:logback-classic")
}
application {
mainClass = "example.Application"
}
Here the only dependency declared is on the logging framework to use however runtime
is to netty
resulting in an application that can be built and run.
If you wish to take the same and build or run it with a different runtime you can pass the micronaut.runtime
property for the build. For example:
./gradlew run -Pmicronaut.runtime=google_function
The above example run the application as a Google Cloud Function.
The available runtimes are:
-
netty
- A Netty server runtime -
jetty
- A Jetty server runtime -
tomcat
- A Tomcat server runtime -
undertow
- An Undertow server runtime -
lambda
- Allows building the application into an AWS Lambda -
oracle_function
- A Project.fn runtime for deploying Oracle Functions -
google_function
- A runtime for deploying Google Functions. -
azure_function
- A runtime for deploying Azure Functions
The advantage of allowing your dependencies to be dictated by the runtime is that you can potentially take the same application and deploy it to any of the above runtimes without changes.
5.6.1. Deploying to AWS Lambda as GraalVM native image
If you are interested in deploying your Micronaut application to AWS Lambda using GraalVM you only need to set the runtime to lambda
and execute ./gradlew buildNativeLambda
.
This task will generate a GraalVM native image inside a Docker container and then it will create the file build/libs/your-app.zip
file ready to be deployed to AWS Lambda using a custom runtime. See more information in Micronaut AWS documentation.
5.7. Packaging the application
By default the plugin doesn’t create a runnable fatjar when running ./gradlew assemble
.
There are a couple of options:
5.7.1. Layered application
The plugin creates a "layered" application in build/docker/main/layers
and from that directory you can run java -jar myapp.jar
.
It works because that directory contains a lib
directory with all the libraries and a resources
directory with the configuration.
Keep in mind that copying the only .jar
file to another directory won’t work.
6. Micronaut GraalVM Plugin
The Micronaut GraalVM plugin is applied automatically by the
Micronaut application plugin (see below)
and it provides tasks to generate a GraalVM native image and also creates the GraalVM resource-config.json
automatically with all the resources from the application.
This plugin can be applied separately if you use the application
plugin without the io.micronaut.application
plugin (but we strongly recommend to switch to the io.micronaut.application
plugin in this case).
7. Micronaut AOT Plugin
Warning
|
The Micronaut AOT module is in experimental stages. Use at your own risk! |
The io.micronaut.aot
plugin provides integration with Micronaut AOT.
Micronaut AOT is a module which aims at pre-computing a number of things at build time in order to provide faster startup times and smaller binaries.
At the moment, the plugin supports optimizing Micronaut applications only (Micronaut libraries or functions will be supported in a future release).
It is capable of generating a number of things:
-
an optimized jar, which is a jar corresponding to the regular application jar, except that it contains some optimizations computed at build time. It may contain, for example, additional classes, or even have different resources.
-
an optimized fat jar, which is the same as the previous one, except that it also embeds all transitive dependencies and is a standalone executable.
-
an optimized native binary which is a GraalVM image compiled with Micronaut AOT optimizations
-
an optimized docker image which is a Docker image containing the optimized application
-
an optimized native docker image which is a Docker image containing the optimized application compiled as a native image
Important
|
Micronaut AOT is a deployment optimization: it adds to build time, in order to make the final application faster to start, or the native images smaller. Therefore, if you use the AOT tasks during development, your feedback cycle will be slower (but the application will start faster). It is a good idea, however, to check the result of the optimization locally, similarly to what you’d do for a native image. |
7.1. Configuration
The io.micronaut.aot
plugin is an extension to the io.micronaut.application
plugin.
plugins {
...
id "io.micronaut.application" version "3.4.1"
id "io.micronaut.aot" version "3.4.1"
...
}
plugins {
...
id("io.micronaut.application") version "3.4.1"
id("io.micronaut.aot") version "3.4.1"
...
}
This will add an aot
DSL block to the micronaut
extension, which can be used to enable optimizations:
micronaut {
...
aot {
// optional, override the Micronaut AOT version
version = "1.0.1"
// optimizations configuration
optimizeServiceLoading = true
convertYamlToJava = true
precomputeOperations = true
cacheEnvironment = true
netty {
enabled = true
}
}
}
micronaut {
...
aot {
// optional, override the Micronaut AOT version
version.set("1.0.0")
// optimizations configuration
optimizeServiceLoading.set(true)
convertYamlToJava.set(true)
precomputeOperations.set(true)
cacheEnvironment.set(true)
netty {
enabled.set(true)
}
}
}
In addition, you can use the aotPlugins
configuration to declare additional AOT modules to be used:
dependencies {
aotPlugins 'io.micronaut.security:micronaut-security-aot:1.0.0'
}
dependencies {
aotPlugins("io.micronaut.security:micronaut-security-aot:1.0.0")
}
Because Micronaut AOT is an extensible optimization engine, not all optimizations are known beforehand by the plugin, which means that not all of them may be accessible via the DSL. For this reason, it is possible to provide a Micronaut AOT configuration file instead:
micronaut {
...
aot {
configFile = file("gradle/micronaut-aot.properties")
}
}
micronaut {
...
aot {
configFile.set(file("gradle/micronaut-aot.properties"))
}
}
Note
|
You can provide both a configuration file and aot DSL optimizations.
The configuration will be merged, by reading the file first, then using the DSL options.
|
If you want to know about all possible optimizations, you can run the createAotSampleConfigurationFiles
which will generate a couple of sample files:
The build/generated/aot/samples/jit/jit.properties
will contain the optimizations which are relevant to an application running in the regular Java virtual machine, for example:
# Checks of existence of some types at build time instead of runtime known.missing.types.enabled = true # A list of types that the AOT analyzer needs to check for existence (comma separated) known.missing.types.list = javax.inject.Inject,io.micronaut.SomeType # Replaces logback.xml with a pure Java configuration (NOT YET IMPLEMENTED!) logback.xml.to.java.enabled = true # Precomputes Micronaut configuration property keys from the current environment variables precompute.environment.properties.enabled = true # Scans reactive types at build time instead of runtime scan.reactive.types.enabled = true # Caches environment property values: environment properties will be deemed immutable after application startup. cached.environment.enabled = true # Scans for service types ahead-of-time, avoiding classpath scanning at startup serviceloading.jit.enabled = true # The list of service types to be scanned (comma separated) service.types = io.micronaut.Service1,io.micronaut.Service2 # A list of implementation types which shouldn't be included in the final application (comma separated) serviceloading.rejected.impls = com.Misc,org.Bar # Converts YAML configuration files to Java configuration yaml.to.java.config.enabled = true # Precomputes property sources at build time sealed.property.source.enabled = true
Another file, build/generated/aot/samples/native/native.properties
will contain the same, but with the options which are relevant to an application compiled to a native image:
# Generates GraalVM configuration files required to load the AOT optimizations graalvm.config.enabled = true # The list of service types to be scanned (comma separated) service.types = io.micronaut.Service1,io.micronaut.Service2 # Checks of existence of some types at build time instead of runtime known.missing.types.enabled = true # A list of types that the AOT analyzer needs to check for existence (comma separated) known.missing.types.list = javax.inject.Inject,io.micronaut.SomeType # Replaces logback.xml with a pure Java configuration (NOT YET IMPLEMENTED!) logback.xml.to.java.enabled = true # Precomputes Micronaut configuration property keys from the current environment variables precompute.environment.properties.enabled = true # Scans reactive types at build time instead of runtime scan.reactive.types.enabled = true # Caches environment property values: environment properties will be deemed immutable after application startup. cached.environment.enabled = true # Scans for service types ahead-of-time, avoiding classpath scanning at startup serviceloading.native.enabled = true # The list of service types to be scanned (comma separated) service.types = io.micronaut.Service1,io.micronaut.Service2 # A list of implementation types which shouldn't be included in the final application (comma separated) serviceloading.rejected.impls = com.Misc,org.Bar # Converts YAML configuration files to Java configuration yaml.to.java.config.enabled = true # Precomputes property sources at build time sealed.property.source.enabled = true
For native images, it is important to always have the graalvm.config.enabled
option set to true
, otherwise the AOT optimizations will not be loaded. The plugin takes care of setting this flag to true
for you.
It is important to understand that Micronaut AOT works at build time. Therefore, some optimizations like conversion of YAML files to Java configuration will effectively disable the ability to change the configuration at runtime.
7.2. Running an optimized application
The plugin provides a couple of tasks aimed at running an optimized application.
The first one, optimizedJar
, will simply run the AOT compiler and produce an "optimized" jar.
If you want to run the application with the resulting jar, you will need to call the optimizedRun
task instead, which will create the jar and then start the application.
If you also have the distribution
plugin applied, the optimized jar will be used to create optimized distributions, in which case you can call the optimizedDistZip
task to create a distribution zip, the optimizedDistTar
to create an optimized distribution tar file, or installOptimizedDist
to install the optimized application to the build/install
directory.
7.3. Running an optimized fat jar
The plugin supports building an optimized fat jar. You will need to apply the shadow
plugin to enable this feature:
plugins {
...
id "com.github.johnrengelman.shadow" version "7.0.0"
...
}
plugins {
...
id("com.github.johnrengelman.shadow") version "7.0.0"
...
}
Then you can generate the fat jar by calling: ./gradlew optimizedJitJarAll
.
The task will generate a fat jar in the build/libs
directory, that you can run using:
java -jar build/libs/myapp-0.1-all-optimized.jar
7.4. Building and running an optimized native application
The plugin creates a new native binary called optimized
.
The GraalVM plugin will then automatically create a couple of tasks for you:
-
the
nativeOptimizedCompile
task will compile a native image with the AOT optimizations -
the
nativeOptimizedRun
task will run the optimized native image (you can call this task directly, it will precompile the native image before)
7.5. Building an optimized Docker image
It is also possible to build an optimized application and package it into a Docker image.
For this, you need to call ./gradlew optimizedDockerBuild
.
It will produce a docker image that you can start using docker run
.
Alternatively, you can call ./gradlew optimizedDockerPush
to push the generated image to your docker registry.
All configuration options which apply to the standard docker image are also available to the optimized Docker images.
7.6. Building an optimized native Docker image
This task also produces a Docker image, but it will build a native image containing the optimized application within a container, in order to produce a Docker image which runs the optimized application natively.
The 2 tasks which are available for this are:
-
optimizedDockerBuildNative
to build the optimized native Docker image -
optimizedDockerPushNative
to push the optimized native Docker image
8. Upgrade notes
8.1. Upgrading from 2.x
When upgrading from the 2.x version of the plugins, you will need to change the configuration of the GraalVM native image builds if you use them.
Typically, instead of configuring image compilation using the task:
nativeImage {
imageName.set("custom")
}
You now need to use the graalvmNative
extension. This extension supports building multiple native images, and the main one is named main
(there is another one for tests, called test
, which runs unit tests natively):
graalvmNative {
binaries {
named("main") {
imageName.set("custom")
}
}
}
Similarly, to compile the native image, you now need to run nativeCompile
instead of nativeImage
.
In addition, the official GraalVM plugin makes use of Gradle toolchains support, which can lead to surprising behavior if you are used to switching between local JDKs. If you are facing errors like this one:
> No compatible toolchains found for request filter: {languageVersion=11, vendor=matching('GraalVM'), implementation=vendor-specific} (auto-detect true, auto-download true)
then we recommend tweaking toolchain detection as described in this section of the documentation.
In any case, make sure to follow the configuration instructions.