Appearance
Introduction to Maven and its Lifecycle | Spring Boot Maven Project
Introduction: The Construction Foreman Analogy
Imagine building a house. You could hire a construction worker and tell them what to build and exactly how to do it: mix three parts cement to one part sand, pour into the mold, wait 24 hours, repeat. That is exhausting and error prone. Or you could hire a foreman who knows all those how to details by heart. You tell the foreman what you want: "Build a foundation." The foreman handles the rest.
Maven is the foreman of your Java project. Before Maven, there was a tool called Ant where you had to specify both what to do and exactly how to do it, providing every step explicitly. Maven changed the game: you tell it what to do and it figures out how.
This chapter covers Maven thoroughly, including its project structure, pom.xml in depth, and the seven phase build lifecycle. By the end you will understand what happens at every step when you run mvn install or mvn package.
What Is Maven?
Maven is a project management tool, not just a build tool. That distinction matters. It helps developers with:
- Build generation: compiling code and producing JARs or WARs
- Dependency resolution: downloading libraries your project needs
- Documentation: generating project reports and documentation
- Project structure: enforcing a standard directory layout
- Plugin execution: running tasks at specific points in the build lifecycle
The key insight is that Maven uses a file called pom.xml (Project Object Model) to understand your project. Every Maven command reads this file first to determine what to do.
The Maven Project Structure
When you generate a Spring Boot project from Spring Initializr with Maven selected, you get this directory layout:
my-app/
├── pom.xml
└── src/
├── main/
│ └── java/
│ └── com/
│ └── example/
│ └── myapp/
│ └── MyAppApplication.java
└── test/
└── java/
└── com/
└── example/
└── myapp/
└── MyAppApplicationTests.javaThis layout is a Maven convention. Every Maven project follows it. The main/java folder holds production code. The test/java folder holds unit tests. Maven knows where to look for each without you telling it.
Understanding pom.xml in Depth
The pom.xml file is the heart of a Maven project. Let us walk through every important section of the pom.xml you get with a Spring Boot project.
The XML Schema Declaration
xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>This declares the XML schema that validates the structure of pom.xml. It ensures the file is well formed and uses the correct elements in the correct places.
The Parent Block
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<relativePath/>
</parent>Every pom.xml can declare a parent POM. Your project inherits configuration from its parent. In Maven, every POM that does not declare a parent implicitly inherits from the Super POM, which defines defaults like the Maven Central repository URL and default plugin configurations.
By declaring spring-boot-starter-parent as the parent, your project inherits:
- Pre configured versions for hundreds of Spring and related dependencies
- Plugin configurations for compilation, testing, and packaging
- Default resource filtering settings
This is why you do not need to specify versions for Spring Boot dependencies. The parent already has them.
Project Coordinates
xml
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>0.0.1-SNAPSHOT</version>These three elements are the coordinates that uniquely identify your project in the Maven ecosystem:
groupId: your organisation or company (e.g.,com.google,com.example)artifactId: the project name (e.g.,my-app,payment-service)version: the current version (e.g.,1.0.0,2.3.1-SNAPSHOT)
Any project in the world can depend on your artifact using these three coordinates.
Properties
xml
<properties>
<java.version>17</java.version>
</properties>Properties are key value pairs for configuration. They can be referenced anywhere in the pom.xml using ${property.name}. For example:
xml
<plugin>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>When Maven processes this, it replaces ${java.version} with 17.
Repositories
xml
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>This tells Maven where to download dependencies. By default (through the Super POM), Maven uses Maven Central. If your company has a private repository (like Nexus or Artifactory), you add its URL here.
Dependency resolution order:
- Maven checks the local repository on your machine (
~/.m2/repository/) - If not found locally, Maven downloads from the remote repository (Maven Central or your company's repo) and caches it locally
Dependencies
xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>These are the libraries your project depends on. Notice there are no version numbers — they are inherited from the parent POM. The scope element controls when a dependency is available:
compile(default): available at compile time and runtimetest: only available during testingprovided: available at compile time but provided by the runtime environment (e.g., a Servlet container)runtime: not needed for compilation but required at runtime
The Maven Build Lifecycle
This is where Maven earns its reputation. The build lifecycle consists of seven sequential phases:
1. validate
2. compile
3. test
4. package
5. verify
6. install
7. deployCritical rule: phases are sequential. If you run phase 4 (package), Maven first runs phases 1, 2, and 3 in order before running package. You cannot skip earlier phases.
Phase 1: Validate
Command: mvn validate
Maven validates that the project structure is correct. It checks that pom.xml is well formed, all required information is present, and the project layout is sane.
By default Maven does not enforce much here, but you can add plugins to this phase. For example, you could add a checkstyle plugin to enforce code formatting standards at validation time, before any code is even compiled:
xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>validate-style</id>
<phase>validate</phase> <!-- runs in validate phase -->
<goals>
<goal>check</goal>
</goals>
<configuration>
<configLocation>checkstyle.xml</configLocation>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>Phase 2: Compile
Command: mvn compile
Maven compiles your Java source code from src/main/java into .class bytecode files. The output goes into target/classes/.
Maven does not ask you to run javac manually. It uses the Maven Compiler Plugin internally, which calls javac on your behalf. You only said "compile" — Maven figured out how.
After running mvn compile:
target/
└── classes/
└── com/
└── example/
└── myapp/
└── MyAppApplication.classPhase 3: Test
Command: mvn test
Maven compiles the test sources from src/test/java and runs all unit tests using the Maven Surefire Plugin. Before running tests, it automatically runs phases 1 and 2 first.
java
// This test class in src/test/java gets compiled and executed in the test phase
@SpringBootTest
class MyAppApplicationTests {
@Test
void contextLoads() {
System.out.println("Running test in Maven test phase");
}
}When you run mvn test, Maven:
- Validates the project
- Compiles main sources
- Compiles test sources
- Executes all test classes matching
*Test.javaor*Tests.java
Phase 4: Package
Command: mvn package
Maven takes the compiled bytecode and packages it into a distributable format. For Spring Boot projects, this is a JAR file. The JAR is placed in target/:
target/
├── classes/
├── test-classes/
└── my-app-0.0.1-SNAPSHOT.jar <-- the packaged artifactThis JAR is a fat JAR (also called an executable JAR) in Spring Boot. It contains all dependencies bundled inside, so anyone can run it with just java -jar my-app-0.0.1-SNAPSHOT.jar.
Phase 5: Verify
Command: mvn verify
Maven runs additional verification tasks on the packaged artifact. This phase is where you add integration tests or static code analysis tools like PMD:
xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.15.0</version>
<executions>
<execution>
<id>static-analysis</id>
<phase>verify</phase> <!-- runs in verify phase -->
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>PMD performs static code analysis and can detect issues like:
- Unused variables and imports
- Empty catch blocks
- Duplicate code blocks
- Overly complex methods
Phase 6: Install
Command: mvn install
Maven takes the packaged JAR and installs it into your local repository at ~/.m2/repository/. After installation, other projects on your machine can depend on it using its coordinates.
The local repository structure:
~/.m2/repository/
└── com/
└── example/
└── my-app/
└── 0.0.1-SNAPSHOT/
└── my-app-0.0.1-SNAPSHOT.jarYou can configure the local repository path by editing ~/.m2/settings.xml:
xml
<settings>
<localRepository>/path/to/your/custom/repo</localRepository>
</settings>Why the local repository matters: When Maven resolves dependencies, it checks the local repository first. If the dependency is there, it uses it directly without making a network call. This makes builds faster and allows offline work after an initial download.
Phase 7: Deploy
Command: mvn deploy
Maven takes the packaged JAR and uploads it to a remote repository. This could be your company's internal Nexus or Artifactory server, or Maven Central for open source projects.
To configure a remote repository, add distributionManagement to your pom.xml:
xml
<distributionManagement>
<repository>
<id>company-releases</id>
<url>https://nexus.yourcompany.com/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>company-snapshots</id>
<url>https://nexus.yourcompany.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>Authentication credentials for the remote repository go in settings.xml (not pom.xml, because credentials should not be committed to source control):
xml
<settings>
<servers>
<server>
<id>company-releases</id>
<username>your-username</username>
<password>your-password</password>
</server>
</servers>
</settings>Phases, Goals, and Plugins: The Full Picture
Each phase contains one or more goals. A goal is a specific task within a phase. Goals are provided by plugins.
Think of it this way:
- Phase: compile
- Plugin:
maven-compiler-plugin - Goal:
maven-compiler-plugin:compile
When you add a plugin to the build and bind it to a phase, you are adding extra goals to that phase. Maven's build lifecycle is extensible through this plugin system.
xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>Maven vs Ant: The Key Difference
| Aspect | Ant | Maven |
|---|---|---|
| Tell it | What AND How | What only |
| Conventions | None (fully manual) | Standard project structure |
| Dependency Management | Manual (copy JARs) | Automatic (central repository) |
| Lifecycle | You define every target | Seven phases, predefined |
| Reuse | Limited | Plugins from Maven Central |
Practical Examples: Running Maven Commands
bash
# Only validate project structure
mvn validate
# Compile source code (also runs validate)
mvn compile
# Run tests (also runs validate + compile)
mvn test
# Create the JAR (also runs validate + compile + test)
mvn package
# Skip tests during packaging (use sparingly)
mvn package -DskipTests
# Install to local repo (runs all phases through install)
mvn install
# Clean the target directory before building
mvn clean install
# Deploy to remote repository
mvn deployThe mvn clean command deletes the target/ directory. Combining it with another phase (mvn clean install) ensures a fresh build every time.
Summary
Maven is far more than a build tool. It is a full project management system that:
- Enforces a standard project structure everyone on your team can navigate immediately
- Manages dependencies from a central repository with compatible version inheritance
- Provides a seven phase lifecycle (validate → compile → test → package → verify → install → deploy) where each phase builds on the previous ones
- Is extensible through plugins that can add custom goals to any lifecycle phase
Understanding Maven deeply means you understand what is happening every time you click "Run" in your IDE or push code to a CI pipeline.
Interview Questions
Q1. What is Maven? How is it different from Ant?
Maven is a project management tool for Java projects. Unlike Ant, where you must specify both what to do and how to do it (providing step by step instructions), Maven follows a convention over configuration philosophy. You declare what you want (e.g., mvn package) and Maven knows how to achieve it using its predefined build lifecycle and plugins. Maven also provides automatic dependency management, which Ant does not.
Q2. What is pom.xml and what are the three coordinates that identify a project?
pom.xml (Project Object Model) is the central configuration file for a Maven project. It describes the project structure, dependencies, build plugins, and repository information. The three coordinates that uniquely identify a project in Maven are groupId (organisation/company), artifactId (project name), and version.
Q3. What are the seven phases of the Maven build lifecycle?
validate— validates the project structurecompile— compiles source code to bytecodetest— runs unit testspackage— bundles compiled code into a JAR or WARverify— runs additional verification (e.g., static analysis)install— installs the artifact to the local repository (~/.m2/)deploy— uploads the artifact to a remote repository
Q4. If you run mvn package, which phases get executed?
Phases 1 through 4 all execute in order: validate, compile, test, and then package. The lifecycle is sequential, so running any phase automatically runs all preceding phases first.
Q5. What is the difference between mvn install and mvn deploy?
mvn install copies the built artifact to your local Maven repository (~/.m2/repository/). Only projects on your local machine can use it as a dependency. mvn deploy uploads the artifact to a remote repository (your company's Nexus, Artifactory, or Maven Central), making it available to the entire team or the public.
Q6. What is a Maven plugin and how do you add a custom goal to a lifecycle phase?
A Maven plugin provides goals (specific tasks). You add a plugin to the <build><plugins> section of pom.xml, specify the goal you want to run, and bind it to a lifecycle phase using the <phase> element inside an <execution> block. When Maven runs that phase, it executes your custom goal along with the phase's default goals.
Q7. What is the local repository and where is it located?
The local repository is a directory on your machine where Maven caches all downloaded dependencies and installed artifacts. By default it is at ~/.m2/repository/. When Maven resolves a dependency, it first checks the local repository. Only if the artifact is absent does it download it from the remote repository. The path can be changed in ~/.m2/settings.xml.
Q8. What is the purpose of the parent block in pom.xml?
The parent block declares that your pom.xml inherits configuration from a parent POM. In a Spring Boot project, the parent is spring-boot-starter-parent, which pre configures dependency versions, plugin settings, and resource filtering. This inheritance is why you do not need to specify version numbers for Spring Boot related dependencies — they are all managed by the parent. If no parent is declared, Maven implicitly inherits from the Super POM.
Q9. What is a Maven starter POM? How is it different from a regular dependency?
A starter POM (like spring-boot-starter-web) is a convenience dependency that has no code of its own. It is a POM file that lists a curated set of other dependencies. When you add a starter to your project, Maven transitively pulls in all those dependencies at compatible versions. A regular dependency is a single library with actual code. Starters are a Spring Boot concept built on top of Maven's dependency system.