1. 简介
Maven 提供了丰富的插件生态来辅助项目构建。但实际开发中,标准插件未必能满足所有需求,这时候就需要自研定制插件。
好在 Maven 提供了一套成熟的插件开发工具链,让整个过程变得简单直接。
本文将手把手带你从零实现一个 Maven 插件,涵盖开发、测试、集成和文档生成全流程。目标不是讲理论,而是直接上干货,踩坑预警,确保你能快速上手。
2. 创建插件项目
我们这次要实现的插件叫 counter-maven-plugin
,功能是统计项目依赖数量。⚠️ 插件命名请严格遵守 Maven 官方规范:<功能名>-maven-plugin
,避免后续解析问题。
首先创建一个标准 Maven 项目,关键在于 pom.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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>counter-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>counter-maven-plugin Maven Mojo</name>
<url>http://maven.apache.org</url>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
</project>
✅ 核心要点:
packaging
必须设为maven-plugin
- 使用 Java 8 编译(兼容性考虑)
你也可以用官方 Archetype 快速生成骨架:
mvn archetype:generate \
-DgroupId=com.baeldung \
-DartifactId=counter-maven-plugin \
-Dversion=0.0.1-SNAPSHOT \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-mojo
生成后建议手动升级依赖到最新稳定版。
3. 开发 Mojo
Mojo(Maven plain Old Java Object)是插件的核心执行单元,你可以理解为一个“接口”或“任务”。一个插件可以包含多个 Mojo。
3.1 添加必要依赖
在 pom.xml
中引入关键依赖:
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
✅ 依赖说明:
maven-plugin-api
:Mojo 运行的基础 APImaven-plugin-annotations
:支持@Mojo
、@Parameter
等注解(推荐使用)maven-project
:用于获取宿主项目的元信息(如依赖列表)
3.2 实现 Mojo 类
创建 DependencyCounterMojo
类,继承 AbstractMojo
并实现 execute
方法:
@Mojo(name = "dependency-counter", defaultPhase = LifecyclePhase.COMPILE)
public class DependencyCounterMojo extends AbstractMojo {
@Parameter(defaultValue = "${project}", required = true, readonly = true)
MavenProject project;
public void execute() throws MojoExecutionException, MojoFailureException {
List<Dependency> dependencies = project.getDependencies();
long numDependencies = dependencies.stream().count();
getLog().info("Number of dependencies: " + numDependencies);
}
}
✅ 关键点解析:
@Mojo(name = "dependency-counter")
:定义目标名称,后续通过mvn counter:dependency-counter
调用defaultPhase = LifecyclePhase.COMPILE
:绑定到编译阶段,无需显式指定 phase@Parameter(defaultValue = "${project}")
:Maven 自动注入当前项目对象,只读getLog().info()
:输出日志,比System.out
更规范
3.3 添加用户可配置参数
上面的 Mojo 只能统计所有依赖。我们来加个 scope
参数,让用户指定统计范围(如 compile
、test
):
@Parameter(property = "scope")
String scope;
修改 execute
方法,加入过滤逻辑:
public void execute() throws MojoExecutionException, MojoFailureException {
List<Dependency> dependencies = project.getDependencies();
long numDependencies = dependencies.stream()
.filter(d -> (scope == null || scope.isEmpty()) || scope.equals(d.getScope()))
.count();
getLog().info("Number of dependencies: " + numDependencies);
}
✅ 参数机制说明:
property = "scope"
表示可通过-Dscope=test
从命令行传参- 若未传参,则
scope
为null
,默认统计所有依赖
更复杂的参数类型(如 List、嵌套对象)可参考官方文档。
4. 插件测试
开发完成,进入验证环节。先安装到本地仓库:
mvn clean install
4.1 命令行直接调用
有两种方式运行插件:
方式一:全限定名(Always works)
mvn com.baeldung:counter-maven-plugin:0.0.1-SNAPSHOT:dependency-counter
方式二:短命名(推荐)
mvn counter:dependency-counter
⚠️ 使用短命名需确保 settings.xml
包含你的 groupId:
<pluginGroups>
<pluginGroup>com.baeldung</pluginGroup>
</pluginGroups>
输出示例:
[INFO] --- counter-maven-plugin:0.0.1-SNAPSHOT:dependency-counter (default-cli) @ counter-maven-plugin ---
[INFO] Number of dependencies: 3
传参测试:
mvn counter:dependency-counter -Dscope=test
4.2 在项目中集成使用
创建一个测试项目 example
,引入几个依赖:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>example</artifactId>
<packaging>pom</packaging>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.13.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
在 <build>
中配置插件:
<build>
<plugins>
<plugin>
<groupId>com.baeldung</groupId>
<artifactId>counter-maven-plugin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>dependency-counter</goal>
</goals>
</execution>
</executions>
<configuration>
<scope>test</scope>
</configuration>
</plugin>
</plugins>
</build>
✅ 注意:
<configuration>
中设置scope
参数- 无需指定 phase,Mojo 已默认绑定
compile
阶段
执行构建:
mvn clean compile
输出:
[INFO] Number of dependencies: 1
完美,只统计了 test
范围的依赖。
📌 提示:生产级插件应编写单元测试和集成测试,Maven 提供了
maven-plugin-testing-harness
支持。
5. 生成插件文档
好插件必须配好文档。Maven 支持自动生成 HTML 文档,步骤如下:
5.1 升级并配置插件版本
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.6.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
5.2 添加项目元信息
<organization>
<name>Baeldung</name>
<url>https://www.baeldung.com/</url>
</organization>
5.3 启用文档报告
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<reportSets>
<reportSet>
<reports>
<report>report</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
5.4 生成文档
mvn site
生成的文档位于 target/site/
,其中 plugin-info.html
是核心文档页:
✅ 文档内容会自动提取 Mojo 的 Javadoc 和参数信息,记得写好注释!
6. 总结
本文带你实战开发了一个 counter-maven-plugin
,覆盖了从项目搭建、Mojo 编写、参数配置、测试验证到文档生成的完整流程。
核心收获:
- ✅ Mojo 是插件的执行单元,通过注解配置
- ✅
maven-plugin-annotations
极大简化开发 - ✅ 命名规范和 groupId 配置影响调用方式
- ✅ 自动生成文档提升可用性
虽然示例功能简单,但骨架完整。你可以基于此模板扩展更复杂的插件,比如代码生成、静态检查、部署发布等。
本文完整代码已托管至 GitHub:https://github.com/eugenp/tutorials/tree/master/maven-modules/maven-custom-plugin