Maven

Last update: 2025-10-16 19:43:25 +0800 +0800
Available translations: 日本語 / 中文(简体) / 中文(繁體)

Maven builds a project by executing plugin goals in lifecycle order. A lifecycle contains ordered phases; invoking a phase executes that phase and every earlier phase in the same lifecycle. Plugins contribute goals, and lifecycle bindings select the goals that run for a project packaging.

Project Model and Coordinates #

The POM identifies an artifact by groupId, artifactId, version, and packaging. Parent POMs, dependency management, and imported BOMs centralize versions without adding an artifact to the classpath. dependencyManagement therefore constrains dependencies only after a child declares them.

Inheritance and aggregation are independent. A child inherits from the POM named by <parent>, while an aggregator lists reactor projects in <modules> and builds them in dependency order. One POM can perform both roles, but a module need not inherit from its aggregator. Inspect the merged model and active profiles with:

sh
mvn help:effective-pom
mvn help:active-profiles

Keep repositories, credentials, and deployment configuration separate:

  • Commit project repositories only when the project requires them.
  • Put credentials and organization-specific mirrors in user or CI settings.xml, not in the POM.
  • Declare dependency and plugin versions explicitly, either directly or through reviewed management sections. A missing plugin version makes a build depend on Maven’s resolution behavior rather than the source tree.

Lifecycles and Phases #

Maven provides the clean, default, and site lifecycles. Day-to-day builds use the default lifecycle:

Phase RangePurpose
validate through process-resourcesValidate the model, generate inputs, and prepare resources.
compile through testCompile production and test code, then execute unit tests.
packageCreate the JAR, WAR, or other distributable artifact.
pre-integration-test through post-integration-testPrepare, execute, and dismantle an integration-test environment.
verifyRun quality checks after tests.
installAdd the artifact to the local repository.
deployPublish the artifact to a remote repository.

mvn verify is a suitable CI baseline because it reaches the verification phase without publishing artifacts. mvn clean verify also removes prior build outputs. The clean lifecycle has pre-clean, clean, and post-clean; clean removes generated build files. The site lifecycle generates and can publish project documentation.

Plugins, Goals, and Executions #

A plugin is build-time code; it is not a project dependency. Configure active build plugins in build/plugins. Use build/pluginManagement to provide a version and shared configuration that children or the same POM must explicitly activate.

xml
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.13.0</version>
      <configuration>
        <release>21</release>
      </configuration>
    </plugin>
  </plugins>
</build>

An execution binds one or more goals to a phase. Packaging-specific default bindings provide common goals such as compiling Java source and creating a JAR. A Mojo’s defaultPhase is used when an execution omits <phase>; it does not bind an arbitrary third-party goal by itself.

xml
<plugin>
  <groupId>org.example</groupId>
  <artifactId>example-maven-plugin</artifactId>
  <version>1.0.0</version>
  <executions>
    <execution>
      <id>generate-sources</id>
      <phase>generate-sources</phase>
      <goals><goal>generate</goal></goals>
    </execution>
  </executions>
</plugin>

Invoke a goal directly with a prefix or complete coordinates:

sh
mvn dependency:tree
mvn org.apache.maven.plugins:maven-dependency-plugin:3.7.1:tree

Prefix resolution can search configured plugin groups and repositories. Complete coordinates are preferable in automation when the POM does not already declare the plugin.

Plugin Internals and Prefix Resolution #

A plugin artifact is identified by <packaging>maven-plugin</packaging>. Its executable units are mojos, which are implemented as subclasses of AbstractMojo. The plugin’s own POM can define a <goalPrefix> through maven-plugin-plugin, and that prefix becomes the short CLI name.

Prefix resolution works in layers:

  1. if the project already declares a plugin with the requested prefix, Maven can resolve it from the effective POM;
  2. otherwise Maven checks the built-in org.apache.maven.plugins group and any extra pluginGroups declared in settings.xml;
  3. if necessary, Maven falls back to artifactId conventions such as maven-XXX-plugin or XXX-maven-plugin.

That resolution model is why mvn dependency:tree works without a fully qualified coordinate, while automation often prefers the explicit groupId:artifactId:version:goal form.

The defaultPhase attribute on @Mojo only supplies a phase for an explicit execution. It does not create an automatic binding for an unofficial plugin. Lifecycle bindings come from the packaging model and Maven’s built-in default bindings, not from the annotation alone.

Dependencies and Scopes #

Maven resolves direct and transitive dependencies into classpaths according to scope:

ScopeMain CompileMain RuntimeTest Compile and Runtime
compileyesyesyes
providedyesnoyes
runtimenoyesyes
testnonoyes

Use provided only when the deployment environment supplies a compatible API, such as a Servlet container. runtime suits drivers and implementations that the compiler does not need. system requires a local file path and bypasses normal repository resolution, so it should not be used for reproducible builds. import applies only to POM dependencies and imports a BOM into dependency management.

Use mvn dependency:tree to find version mediation and exclusions. Maven’s nearest-definition rule selects among conflicting transitive versions; equal depth is resolved by declaration order. A direct declaration or dependencyManagement entry makes the choice explicit. Exclusions apply only to the dependency path where they are declared, so prefer management or a BOM to scattered exclusions.

Repositories, Mirrors, and Settings #

A repository is an artifact source. A mirror is a settings.xml rule that redirects requests for selected repositories; it does not add dependencies or replace repository authorization policy.

xml
<mirrors>
  <mirror>
    <id>company-proxy</id>
    <mirrorOf>central</mirrorOf>
    <url>https://repository.example.invalid/maven-central</url>
  </mirror>
</mirrors>

The global settings file is under the Maven installation and the user settings file is ~/.m2/settings.xml. CI should provide a minimal settings file through its secret-management mechanism. Do not store repository passwords in a POM. Maven’s <relocation> metadata lets a publisher redirect an obsolete coordinate to a replacement coordinate.

Maven Wrapper #

Commit mvnw, mvnw.cmd, and .mvn/wrapper/ so developers and CI use the declared Maven distribution:

sh
mvn wrapper:wrapper -Dmaven=3.9.9
./mvnw clean verify

Review the distribution URL and checksum when updating the wrapper. The wrapper pins Maven itself; plugin and dependency versions still require POM management.

Comments

Read or comment on GitHub (sign-in required to comment)