17.5.1 Automatic Restart
There are various ways to achieve reloading of classes on the JVM, all have their advantages and disadvantages. The following are possible ways to achieve reloading without restarting the JVM:
JVM Agents - A JVM agent like JRebel can be used, however these can produce unusual errors, may not support all JDK versions and can result in cached / stale classes.
ClassLoader Reloading - Class Loader based reloading is a popular solution used by most JVM frameworks, however it once again can lead to cached / stale classes, memory leaks and weird errors if the incorrect classloader is used at any moment.
Debugger HotSwap - The Java debugger supports hotswapping of changes at runtime, but only supports a few use cases.
Given the problems with existing solutions and a lack of a way built into the JVM to reload changes, the safest and best solution to reloading, and the one recommended by the Micronaut team, is to use automatic application restart via third-party tool.
Micronaut’s startup time is fast and automatic restart leads to a clean slate without potential hard to debug problems cropping up or memory leaks.
Configuring File Watch
The following demonstrates how to configure Micronaut to automatically stop the application if a change occurs to an external file.
You can create a new application with the file-watch feature already configured using the CLI with the command mn create-app myapp —features file-watch |
First configure your application.yml
file to enable file watch:
Configuring File Watch
micronaut:
io:
watch:
paths: src/main
restart: true
By setting micronaut.io.watch.paths
what happens is that Micronaut will fire a FileChangedEvent if any file is changed. Setting micronaut.io.watch.restart
tells Micronaut to stop the server if a file is changed.
The micronaut.io.watch.paths setting can be used for more than just automatic restart, you can use this setting to monitor for file changes within your production application. |
File Watch and Mac OS X
The native JVM implementation of the WatchService
interface for Mac OS X using polling which is slow. To improve file watch performance add the following dependencies to your build if you are using OS X:
Gradle - Configuring Native File Watch on Mac OS X
configurations {
developmentOnly
}
dependencies {
// Automatically added with the 'file-watch' feature in the CLi
developmentOnly "io.micronaut:micronaut-runtime-osx"
...
developmentOnly "net.java.dev.jna:jna"
developmentOnly "io.methvin:directory-watcher"
}
run.classpath += configurations.developmentOnly
A custom developmentOnly configuration is used to ensure the dependencies don’t go into the production JAR. |
Or with Maven:
<dependency>
<groupId>io.methvin</groupId>
<artifactId>directory-watcher</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<scope>provided</scope>
</dependency>
The provided scope is used to ensure the dependencies don’t go into the production JAR. |
Restarting the Server
Once set to true
the micronaut.io.watch.restart
setting will stop the server when a file changes, it is then up to an external process to restart the server. For example, with Gradle this can be achieved with a continuous build:
Automatic Restart with Gradle Continuous Build
$ gradle run --continuous
You can also use a Kubernetes replication controller to restart the application if this feature is used in production |
Maven does not have an equivalent feature, however you can achieve a similar effect with a bash script:
Automatic Restart with Maven and Bash
#!/usr/bin/env sh
while true; do
./mvn compile exec:exec
sleep 1s
done
If automatic restart is for some reason not your preferred approach then you can use most JVM agents with Micronaut. See the following sections for a description on how to setup JVM agents.