I’ve been recently developing a Spring Boot application, and to speed up my development speed, I added Developer Tools as a dependency.
By default, classes loaded in the HotSpot JVM can be updated only if the later runs in debug mode, and only for changes regarding method implementation. This means adding an attribute to an class requires a full restart.
DevTools is an improvement over that. It works by tweaking the standard classloading mechanism: one classloader is dedicated to libraries, another one to the project’s classes. If a class changes and if it cannot be reloaded by HotSpot, instead of restarting the whole JVM, the second classloader is simply discarded and all classes are loaded again. Since the number of classes in the project is very small compared to the number of classes in libraries and the JDK, this approach is very fast compared to a full restart. Plus, one benefits from keeping the session, the caches, etc.
All of this allows for shorter development cycles. It also is a free alternative to JRebel - albeit limited to Spring Boot-based projects.
To distribute Spring Boot apps in Docker containers, I’m using the Maven Jib plugin. Jib is able to create Docker images, without the need of any Docker runtime!
Because Jib is a Maven plugin, it’s plugged into the Maven configuration and it’s able to infer a lot. The includes the main class and the JAR dependencies. Because of that, the default creates a Docker image with a dedicated
java command e.g.:
java -cp /app/resources:/app/classes:/app/libs/* \ ch.frankel.boot.zerodowntime.ZeroDowntimeApplicationKt
Thus, it’s not an executable JAR that gets distributed, but just a directory structure. The main benefit is that the build lifecycle can limit itself to the compile phase. As a corollary, the execution of the Maven Spring Boot plugin is neither necessary nor useful.
Developer tools are automatically disabled when running a fully packaged application. If your application is launched from java -jar or if it is started from a special classloader, then it is considered a "production application".
Unfortunately, since the application is not run as a JAR, the DevTools JAR itself is included in the image dependencies. This allows remote access to the application. There are reasons to allow that, but in all other cases, this should be considered a security issue.
Let’s fix that.
The first step is to isolate the DevTools JAR into a dedicated Maven profile:
<profiles> <profile> <id>dev</id> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> </dependencies> </profile> </profiles>
Now, this profile can be used, hopefully only during development time. Yet, Maven profiles are applied at build time, not runtime. Hence, in IntelliJ IDEA, it doesn’t help to change the settings of the Run Configuration.
Instead, go to the Maven view, find the Profiles item, and check the relevant one.
At this point, every IntelliJ-based build will use the
dev profile that include DevTools, while the final Jib-based Docker image won’t.