Tags: maven, java, build-tools, pom, dependency-management, plugins, lifecycle
Level: intermediate
TL;DR: Build lifecycle, dependency resolution rules, and plugin execution phases for Java applications managed via declarative XML.
Project Object Model (pom.xml) defines declarative metadata, dependencies, build settings, and plugins.
Built-in lifecycles include default (core build/deploy), clean (artifact removal), and site (documentation generation).
Default build lifecycle phases execute sequentially: validate, compile, test, package, verify, install, and deploy.
Transitive dependency resolution uses nearest-definition-first rather than highest version number.
Dependency scope dictates classpath visibility: compile, provided, runtime, test, system, and import.
Maven coordinates uniquely identify artifacts via groupId, artifactId, version, and optional packaging or classifier.
Plugins attach specific goals to lifecycle phases to perform concrete tasks during the build.
Multi-module builds configure parent POMs with packaging pom to manage aggregation and dependencyManagement.
Profiles allow environment-specific overrides triggered by explicit flags, OS, or JDK version.
Q: How does Maven resolve version conflicts between transitive dependencies?R: Maven uses the nearest-definition strategy in the dependency tree. If two versions exist at the same depth, the first declared one wins, which I override explicitly via <dependencyManagement> when necessary.
Q: What is the difference between <dependencies> and <dependencyManagement>?R: <dependencyManagement> centralizes version and exclusion rules without adding the artifact to the classpath. The actual <dependencies> section inherits those versions and imports the libraries into the build.
Q: Why would you use the provided dependency scope?R: I use provided when the dependency is required at compile time and test time, but supplied at runtime by the container or runtime environment, such as the Servlet API.
Q: What is the exact difference between mvn install and mvn deploy?R: mvn install copies the packaged artifact into my local repository (~/.m2/repository). mvn deploy uploads the artifact to a shared remote repository like Nexus or Artifactory.
Omitting versions in <dependencyManagement> causes build reproducibility issues across different machines.
Conflicting transitive libraries caused by the nearest-definition rule instead of highest-version resolution.
Running clean during rapid iterations slows feedback; use it when stale generated sources corrupt builds.
Binding heavy plugin goals to premature phases like compile instead of verify or package.
Misunderstanding pom.xml inheritance vs aggregation: parent projects require inheritance, modules require aggregator projects.
# Force update of snapshots and releases from remote repository
mvn clean install -U
# Display dependency resolution tree and identify conflict paths
mvn dependency:tree -Dverbose
# Run specific plugin goal without executing entire lifecycle
mvn dependency:analyze
# Build specific submodule and its dependencies in a reactor project
mvn clean install -pl :sub-module-name -am
# Run single unit test method
mvn test -Dtest=UserServiceTest#testFindById
XML
<!-- Example dependency exclusion and dependencyManagement -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
[ ] Maven Reactor execution order algorithms
[ ] Plugin execution configuration: <executions> vs <configuration> placement
[ ] BOM (Bill of Materials) pattern using scope=import
[ ] Maven Surefire vs Failsafe plugin phases and naming conventions