12.2.1.1 Java Maven Build
A focused guide to Java Maven Build, connecting core concepts with practical Docker and container operations.
A Java Maven build within Docker uses Maven's own build lifecycle to compile, test, and package a Java application, typically within a build stage of a multi-stage Dockerfile, taking advantage of Maven's dependency caching to keep rebuilds efficient.
The Basic Maven Build Stage
A build stage uses an image with Maven and an appropriate JDK pre-installed.
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
This produces a built artifact (typically a JAR or WAR file) within the build stage, ready to be copied into a final, leaner runtime stage.
Leveraging Maven's Dependency Caching Through Layer Ordering
Copying pom.xml before the full source code allows Docker to cache the dependency resolution step separately from the actual compilation, avoiding unnecessary re-downloads when only application code (not dependencies) has changed.
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package
If only files under src change between builds, the dependency resolution layer remains cached, since pom.xml itself didn't change.
Skipping Tests During the Image Build (With Appropriate Caution)
Skipping tests during this specific build step is sometimes done to speed up image construction, with the understanding that tests should still run as their own, separate step in a CI pipeline.
RUN mvn package -DskipTests
steps:
- run: mvn test
- run: docker build -t myapp .
Using a Local Maven Repository Cache Across Builds
Mounting a cache for Maven's local repository, using BuildKit's cache mount feature, can further speed up repeated builds by persisting downloaded dependencies across separate build invocations.
RUN --mount=type=cache,target=/root/.m2 mvn package
Why Java Maven Build Matters
Properly structuring a Maven-based build stage, with attention to dependency caching and appropriate test handling, is essential for keeping Java image builds reasonably fast and efficient, particularly for projects with substantial dependency trees.