【Maven】自定义Maven插件

场景:

1、自定义一个插件目标 timer,用于显示当前日期时间。

2、将 timer 绑定到 validate 阶段。

调研

1、maven-clean-plugin

下载 maven-clean-plugin 插件的源码,在本地使用 IDEA 打开

可以看到,maven-clean-plugin 插件是由单个 Maven 工程实现的,CleanMojo 是 clean 目标的实现类。

2、maven-compiler-plugin

下载 maven-compiler-plugin 插件的源码,在本地使用 IDEA 打开

可以看到,maven-compiler-plugin 插件是由单个 Maven 工程实现的,CompilerMojo 是 compile 目标的实现类,TestCompilerMojo 是 testCompile 目标的实现类。

3、maven-surefire-plugin

下载 maven-surefire-plugin 插件 2.14.2 版本的源码,在本地使用 IDEA 打开

可以看到,maven-surefire-plugin 插件整体是一个聚合工程,在聚合工程中有一个 module 用于实现 test 目标。

4、maven-jar-plugin

下载 maven-jar-plugin 插件的源码,在本地使用 IDEA 打开

可以看到,maven-jar-plugin 插件是由单个 Maven 工程实现的,JarMojo 是 clean 目标的实现类。

5、maven-install-plugin

下载 maven-install-plugin 插件的源码,在本地使用 IDEA 打开

可以看到,maven-install-plugin 插件是由单个 Maven 工程实现的,InstallMojo 是 install 目标的实现类。

6、maven-deploy-plugin

下载 maven-deploy-plugin 插件的源码,在本地使用 IDEA 打开

可以看到,maven-deploy-plugin 插件是由单个 Maven 工程实现的,DeployMojo 是 deploy 目标的实现类。

总结:

1、项目的结构

一般情况下,一个插件对应一个项目,在 src/main/java 目录下实现插件的目标,实现类的类名是"目标名Mojo"。maven-surefire-plugin 较为特殊,定义了一个聚合工程,其 test 目标是在自模块 maven-surefire-plugin 中实现的。总体来看,一个插件对应一个工程如果插件较为复杂,可以考虑创建聚合工程,使用子模块实现插件目标

2、pom 文件的项目描述符

groupId 一般为公司域名倒序
artifactId 插件的名称
version 插件的版本
packaging 必须设置为 maven-plugin
dependencies 必须引入 maven-plugin-api 和 maven-plugin-annotations

说明

  • maven-plugin-api:这个依赖提供了编写 Maven 插件所需的核心 API。它包括了Mojo接口和一些其他的基础类,这些是你在创建自己的 Maven 目标(goals)时所必需的。
  • maven-plugin-annotations:此依赖包含用于注解 Maven 插件组件的注解,比如@Mojo@Parameter等。这些注解帮助描述插件的行为和配置,并且是在编译期由 Maven 插件工具处理的。

3、其他标签元素:

  • 还可以指定其他信息,如插件名称 name、描述 description、开始开发的年份 inceptionYear、贡献者 contributor 等。

开发Maven插件的步骤

1、创建 Maven 工程

  • 在工程的 pom 文件中设置标签,如 GAV、packaging、description等,其中前两者必须设置。
  • 在 pom 文件中引入必要的依赖 maven-plugin-api 和 maven-plugin-annotations。

2、创建目标类Mojo

  • 使用 @Mojo 注解,name 属性指定目标名称
  • 重写 execute 方式,实现目标的功能逻辑
  • 添加属性

3、打包插件工程,安装到本地仓库或部署到远程仓库(私服)

4、引用插件,运行插件

  • 直接运行插件
  • 或将目标绑定到特定生命周期阶段(可选)
  • 无论选择哪种运行方式,都可以在命令行指定参数

环境设置

1、JDK:1.8.0_131

2、Maven:Apache Maven 3.8.8

3、IntelliJ IDEA:2024.1.1 (Ultimate Edition)

实现

1、创建工程

maven-clean-plugin 是 Maven 中相对简单的一个插件,我们可以仿照该插件的目录结构创建一个项目。

(1) 选择 Maven Archetype

  • 在 Archetype 下拉框中选择 org.apache.maven.archetypes:maven-archetype-plugin
  • 设置 ArtifactId
  • Create
    控制台打印:
Shell 复制代码
C:\Softwares\Developer_Kits\JDK\jdk1.8.0_131\bin\java.exe -Dmaven.multiModuleProjectDirectory=C:\Users\ ......
[INFO] Scanning for projects...
Downloading from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-archetype-plugin/maven-metadata.xml
Downloaded from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-archetype-plugin/maven-metadata.xml (1.1 kB at 1.0 kB/s)
Downloading from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-archetype-plugin/3.3.1/maven-archetype-plugin-3.3.1.pom
Downloaded from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-archetype-plugin/3.3.1/maven-archetype-plugin-3.3.1.pom (10 kB at 21 kB/s)
Downloading from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/maven/archetype/maven-archetype/3.3.1/maven-archetype-3.3.1.pom
Downloaded from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/maven/archetype/maven-archetype/3.3.1/maven-archetype-3.3.1.pom (10 kB at 20 kB/s)
Downloading from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/groovy/groovy-bom/4.0.23/groovy-bom-4.0.23.pom
Downloaded from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/groovy/groovy-bom/4.0.23/groovy-bom-4.0.23.pom (27 kB at 48 kB/s)
Downloading from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-archetype-plugin/3.3.1/maven-archetype-plugin-3.3.1.jar
Downloaded from myphoenix-nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-archetype-plugin/3.3.1/maven-archetype-plugin-3.3.1.jar (99 kB at 165 kB/s)
[INFO] 
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] >>> maven-archetype-plugin:3.3.1:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO] 
[INFO] <<< maven-archetype-plugin:3.3.1:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO] 
[INFO] 
[INFO] --- maven-archetype-plugin:3.3.1:generate (default-cli) @ standalone-pom ---

......

[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-plugin:1.2
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: cn.myphoenix
[INFO] Parameter: artifactId, Value: timer-maven-plugin
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: cn.myphoenix
[INFO] Parameter: packageInPathFormat, Value: cn/myphoenix
[INFO] Parameter: package, Value: cn.myphoenix
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: groupId, Value: cn.myphoenix
[INFO] Parameter: artifactId, Value: timer-maven-plugin
[INFO] Project created from Archetype in dir: C:\Users\MyPhoenix\AppData\Local\Temp\archetypetmp\timer-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  27.799 s
[INFO] Finished at: 2024-12-06T20:53:56+08:00
[INFO] ------------------------------------------------------------------------

(2) 修改pom文件

  • GAV
  • packaging 必须设置为 maven-plugin
  • 必须引入 maven-plugin-api 和 maven-plugin-annotations,这样才能在编写 Mojo 目标类时继承 AbstractMojo 和使用注解。
  • maven-plugin-plugin 可选,下面的方式是使用 aven-plugin-plugin:helpmojo 生成自定义插件的 help 目标。(官方推荐这样做)
  • properties 标签内部定义编码方式、JDK 版本、源码和编译代码的版本等。
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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>cn.myphoenix</groupId>
  <artifactId>timer-maven-plugin</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>maven-plugin</packaging>

  <name>timer-maven-plugin Maven Plugin</name>
  <description>The Maven Timer Plugin is a plugin that displays the current time in the default timezone.</description>
  <inceptionYear>2024</inceptionYear>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- 配置Maven编译的时候采用的编译器版本 -->
    <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    <!-- 指定源代码是什么版本的,如果源码和这个版本不符将报错,Maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-source参数 -->
    <maven.compiler.source>1.8</maven.compiler.source>
    <!-- 该命令用于指定生成的class文件将保证和哪个版本的虚拟机进行兼容,Maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-target参数 -->
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven-plugin-tools.version>3.13.1</maven-plugin-tools.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>3.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- dependencies to annotations -->
    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>${maven-plugin-tools.version}</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-plugin-plugin</artifactId>
          <version>${maven-plugin-tools.version}</version>
          <executions>
            <execution>
              <id>help-mojo</id>
              <goals>
                <!-- good practice is to generate help mojo for plugin -->
                <goal>helpmojo</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
        <configuration>
          <source>8</source>
          <target>8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

自动生成的 xml 版本:

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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>cn.myphoenix</groupId>
  <artifactId>timer-maven-plugin</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>maven-plugin</packaging>

  <name>timer-maven-plugin Maven Plugin</name>

  <!-- FIXME change it to the project's website -->
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>2.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>3.2</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.codehaus.plexus</groupId>
      <artifactId>plexus-utils</artifactId>
      <version>3.0.8</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-plugin-plugin</artifactId>
        <version>3.2</version>
        <configuration>
          <goalPrefix>timer-maven-plugin</goalPrefix>
          <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
        </configuration>
        <executions>
          <execution>
            <id>mojo-descriptor</id>
            <goals>
              <goal>descriptor</goal>
            </goals>
          </execution>
          <execution>
            <id>help-goal</id>
            <goals>
              <goal>helpmojo</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>run-its</id>
      <build>

        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-invoker-plugin</artifactId>
            <version>1.7</version>
            <configuration>
              <debug>true</debug>
              <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
              <pomIncludes>
                <pomInclude>*/pom.xml</pomInclude>
              </pomIncludes>
              <postBuildHookScript>verify</postBuildHookScript>
              <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
              <settingsFile>src/it/settings.xml</settingsFile>
              <goals>
                <goal>clean</goal>
                <goal>test-compile</goal>
              </goals>
            </configuration>
            <executions>
              <execution>
                <id>integration-test</id>
                <goals>
                  <goal>install</goal>
                  <goal>integration-test</goal>
                  <goal>verify</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>

      </build>
    </profile>
  </profiles>
</project>

(3) 添加版本控制(可选)

将不需要版本控制的文件或文件夹添加到 .gitignore 中。

2、创建目标类Mojo

  • Javadoc 注释设置目标的 description 为"时间提醒器",创建目标后会解析注释内容
  • 使用 @Mojo 注解的 name 属性为目标设置名称 timer。
  • 继承 AbstractMojo 抽象类,并重写 execute 方法。
Java 复制代码
package cn.myphoenix.timer;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;

import java.time.LocalDateTime;

/**
 * 时间提醒器
 *
 * @author: larry_lwh
 * @date: 2024-12-06 21:09
 * @description: 时间提醒 Mojo
 **/
@Mojo(name = "timer")
public class TimerMojo extends AbstractMojo {
    public void execute() throws MojoExecutionException, MojoFailureException {
        this.getLog().info("现在是北京时间:" + LocalDateTime.now());
    }
}

查看自定义目标的详细信息:mvn help:describe -Dplugin="cn.myphoenix:timer-maven-plugin"

Shell 复制代码
(base) PS C:\...\maven_00> mvn help:describe -Dplugin="cn.myphoenix:timer-maven-plugin"               
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-help-plugin:3.5.1:describe (default-cli) @ maven_00 ---
[INFO] cn.myphoenix:timer-maven-plugin:1.0-SNAPSHOT

Name: timer-maven-plugin Maven Plugin
Description: The Maven Timer Plugin is a plugin that displays the current
  time in the default timezone.
Group Id: cn.myphoenix
Artifact Id: timer-maven-plugin
Version: 1.0-SNAPSHOT
Goal Prefix: timer

This plugin has 2 goals:

timer:help
  Description: Display help information on timer-maven-plugin. Call mvn
    timer:help -Ddetail=true -Dgoal= to display parameter details.

timer:timer
  Description: 时间提醒器

For more information, run 'mvn help:describe [...] -Ddetail'

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.573 s
[INFO] Finished at: 2024-12-06T21:54:25+08:00
[INFO] ------------------------------------------------------------------------

3、打包插件,并安装到本地仓库

我们开发插件的目的就是本地项目或者其他开发人员要用,因此,需要将插件工程打包,并安装到本地仓库或部署到远程仓库(私服)。

在当前工程执行mvn clean install,以将插件工程打包并安装到本地 Maven 仓库。当然也可以发布到 Nexus 私服。

控制台打印:

Shell 复制代码
(base) PS C:\...\timer-maven-plugin> mvn clean install
[INFO] Scanning for projects...
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ timer-maven-plugin ---
[INFO] Deleting C:\Coding_Gallery\Intellij_IDEA_Workspace\timer-maven-plugin\target
[INFO]
[INFO] --- maven-plugin-plugin:3.13.1:helpmojo (help-mojo) @ timer-maven-plugin ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ timer-maven-plugin ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Coding_Gallery\Intellij_IDEA_Workspace\timer-maven-plugin\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.13.0:compile (default-compile) @ timer-maven-plugin ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 2 source files with javac [debug target 8] to target\classes
[INFO] 
[INFO] --- maven-plugin-plugin:3.13.1:descriptor (default-descriptor) @ timer-maven-plugin ---
[INFO] Using 'UTF-8' encoding to read mojo source files.
[INFO] java-annotations mojo extractor found 2 mojo descriptors.
[INFO] java-javadoc mojo extractor found 0 mojo descriptor.
[INFO] ant mojo extractor found 0 mojo descriptor.
[INFO] bsh mojo extractor found 0 mojo descriptor.
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ timer-maven-plugin ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Coding_Gallery\Intellij_IDEA_Workspace\timer-maven-plugin\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.13.0:testCompile (default-testCompile) @ timer-maven-plugin ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ timer-maven-plugin ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ timer-maven-plugin ---
[INFO] Building jar: C:\Coding_Gallery\Intellij_IDEA_Workspace\timer-maven-plugin\target\timer-maven-plugin-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-plugin-plugin:3.13.1:addPluginArtifactMetadata (default-addPluginArtifactMetadata) @ timer-maven-plugin ---
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ timer-maven-plugin ---
[INFO] Installing C:\Coding_Gallery\Intellij_IDEA_Workspace\timer-maven-plugin\target\timer-maven-plugin-1.0-SNAPSHOT.jar to C:\Softwares\Developer_Kits\apache-maven-3.8.8\repository\cn\myphoenix\timer-maven-plugin\1.0-SNAPSHOT\timer-maven-plugin-1.0-SNAPSHOT.jar
[INFO] Installing C:\Coding_Gallery\Intellij_IDEA_Workspace\timer-maven-plugin\pom.xml to C:\Softwares\Developer_Kits\apache-maven-3.8.8\repository\cn\myphoenix\timer-maven-plugin\1.0-SNAPSHOT\timer-maven-plugin-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.505 s
[INFO] Finished at: 2024-12-06T21:20:09+08:00
[INFO] ------------------------------------------------------------------------

可以看到,packaging 为 maven-plugin,打成的包也是 jar 包:timer-maven-plugin-1.0-SNAPSHOT.jar

4、运行插件

在其他任意一个项目的 pom 文件中引入自定义的 timer-maven-plugin 插件:

XML 复制代码
<build>
    <plugins>
        <plugin>
            <groupId>cn.myphoenix</groupId>
            <artifactId>timer-maven-plugin</artifactId>
            <version>1.0-SNAPSHOT</version>
        </plugin>
    </plugins>
</build>

方式一

命令行直接执行插件mvn cn.myphoenix:timer-maven-plugin:timer

控制台打印如下:插件运行成功

Shell 复制代码
(base) PS C:\...\maven_00> mvn cn.myphoenix:timer-maven-plugin:timer
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- timer-maven-plugin:1.0-SNAPSHOT:timer (default-cli) @ maven_00 ---
[INFO] 现在是北京时间:2024-12-06T21:25:50.739
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.226 s
[INFO] Finished at: 2024-12-06T21:25:50+08:00
[INFO] ------------------------------------------------------------------------

方式二:使用前缀名

我们自定义的插件是否也有前缀名?

使用 help 插件的 describe 目标查看一下我们自定义的 timer-maven-timer 插件的详细信息:

Shell 复制代码
(base) PS C:\...\maven_00> mvn help:describe -Dplugin="cn.myphoenix:timer-maven-plugin"   
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-help-plugin:3.5.1:describe (default-cli) @ maven_00 ---
[INFO] cn.myphoenix:timer-maven-plugin:1.0-SNAPSHOT

Name: timer-maven-plugin Maven Plugin
Description: (no description available)
Group Id: cn.myphoenix
Artifact Id: timer-maven-plugin
Version: 1.0-SNAPSHOT
Goal Prefix: timer

This plugin has 2 goals:

timer:help
  Description: Display help information on timer-maven-plugin. Call mvn
    timer:help -Ddetail=true -Dgoal= to display parameter details.

timer:timer
  Description: (no description available)

For more information, run 'mvn help:describe [...] -Ddetail'

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.603 s
[INFO] Finished at: 2024-12-06T21:28:54+08:00
[INFO] ------------------------------------------------------------------------

竟然有前缀名,可是我们并没有配置啊。

在 Maven 官网给出了插件命名规范:

XML 复制代码
You will typically name your plugin <yourplugin>-maven-plugin.
Calling it maven-<yourplugin>-plugin (note "Maven" is at the beginning of the plugin name) is strongly discouraged since it's a reserved naming pattern for official Apache Maven plugins maintained by the Apache Maven team with groupId org.apache.maven.plugins.
Using this naming pattern is an infringement of the Apache Maven Trademark.

也就是说,我们定义的格式只要遵循<name>-maven-pluginmaven-<name>-plugin,Maven 就会将 name 设置为插件的前缀名。我们一般使用前一种插件命名方式,因为后一种可能会侵权。

因此,将插件名设置为 timer-maven-plugin,Maven 会帮忙设置前缀名是 timer。

简化命令行:mvn timer:timer

Shell 复制代码
(base) PS C:\...\maven_00> mvn timer:timer
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- timer-maven-plugin:1.0-SNAPSHOT:timer (default-cli) @ maven_00 ---
[INFO] 现在是北京时间:2024-12-06T21:35:49.901
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.185 s
[INFO] Finished at: 2024-12-06T21:35:49+08:00
[INFO] ------------------------------------------------------------------------

5、将插件目标绑定到生命周期阶段上(可选)

方式一:pom文件显式绑定(官方使用)

在引入自定义插件 timer-maven-pluging 的项目 pom 文件中,显式地将插件目标绑定到 default 生命周期的 validate 阶段:

XML 复制代码
<build>
    <plugins>
        <plugin>
            <groupId>cn.myphoenix</groupId>
            <artifactId>timer-maven-plugin</artifactId>
            <version>1.0-SNAPSHOT</version>
            <executions>
                <execution>
                    <phase>validate</phase>
                    <id>default-timer</id>
                    <goals>
                        <goal>timer</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

执行mvn validate命令验证:绑定成功

Shell 复制代码
(base) PS C:\Coding_Gallery\Intellij_IDEA_Workspace\maven_lifecycle_plugin_demo\maven_00> mvn validate
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- timer-maven-plugin:1.0-SNAPSHOT:timer (default-timer) @ maven_00 ---
[INFO] 现在是北京时间:2024-12-06T22:13:24.689
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.221 s
[INFO] Finished at: 2024-12-06T22:13:24+08:00
[INFO] ------------------------------------------------------------------------

方式二:@Mojo注解的defaultPhase属性执行

在 Mojo 类的 @Mojo 注解中使用 defaultPhase 属性绑定阶段

Java 复制代码
@Mojo(name = "timer", defaultPhase = LifecyclePhase.VALIDATE)
public class TimerMojo extends AbstractMojo {
    public void execute() throws MojoExecutionException, MojoFailureException {
        this.getLog().info("现在是北京时间:" + LocalDateTime.now());
    }
}

但是,使用这种方式需要在引入自定义插件 timer-maven-plugin 处使用 goal 标签,phase 标签可不指定。如果不指定 goal 标签,就无法绑定。pom 如下配置,@Mojo 注解的 defaultPhase 属性才会生效:

XML 复制代码
<build>
    <plugins>
        <plugin>
            <groupId>cn.myphoenix</groupId>
            <artifactId>timer-maven-plugin</artifactId>
            <version>1.0-SNAPSHOT</version>
            <executions>
                <execution>
                    <id>default-timer</id>
                    <goals>
                        <goal>timer</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

思考

我们在平时使用官方提供的插件,例如 maven-surefire-plugin 时好像并没有在 pom 文件中显式声明。而且,就算显式声明了,也不需要像方式二那样还要使用 executions -> execution -> goals -> goal。

演示 1:没有显式引入 maven-surefire-plugin 插件

如下所示,没有显式引入该插件,依然可以使用

Shell 复制代码
(base) PS C:\...\maven_00> mvn clean
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven_00 ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.218 s
[INFO] Finished at: 2024-12-07T10:03:39+08:00
[INFO] ------------------------------------------------------------------------

演示二:显式引入 maven-surefire-plugin 插件,但不做任何配置

pom 文件配置如下:

XML 复制代码
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.5.0</version>
        </plugin>
    </plugins>
</build>

运行结果如下:

可以看到,即使没有做任何配置,如显式声明 goal 标签,我们依旧可以成功执行插件目标。

Shell 复制代码
(base) PS C:\...\maven_00> mvn clean
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven_00 ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.193 s
[INFO] Finished at: 2024-12-07T10:06:24+08:00
[INFO] ------------------------------------------------------------------------

所以,为什么会这样呢?自定义插件需要显式声明 goal,而官方插件就不需要显式声明 goal。

这是因为 Maven 硬编码了一些插件目标和生命周期阶段的绑定,我们自己项目的 pom 文件会继承这些硬编码的绑定,例如 maven-clean-plugin 的 clean 目标和 clean 生命周期的 clean 阶段已经绑定了,我们直接用就行。

然而,我们自定义的插件并没有硬编码式的绑定到某些阶段上,所以,在引入插件时,需要在 pom 文件中显式地将其目标绑定到阶段上。

总结:

在将官方插件目标或自定义插件目标绑定到某个阶段上时,需要我们在引入插件时显式地声明插件和目标的绑定,也就是方式一。

6、参数设置

平时我们在将本地项目打包安装到本地仓库或打包部署到私服上时,会执行如下命令:

Shell 复制代码
# 打包并安装到本地仓库
mvn clean install -DskipTests=true

# 打包并部署到私服
mvn clean deploy -DskipTests=true

观察到,有一个参数配置 -DskipTests=true。这个参数配置是哪里来的呢?

我们可以顺藤摸瓜,既然我们执行的是插件目标,而目标又是一个 Mojo 类,那参数应该是类中的属性吧?

这个猜测是正确的,上面命令行中配置的参数的确是 Mojo 类的属性。我们配置参数,实际上就是为属性赋值。

之前提到了查看目标参数的命令,我们不妨查看一下 maven-clean-plugin:clean 的目标类的属性。

结果如下:

Shell 复制代码
(base) PS C:\...\maven_00> mvn clean:help -Dgoal=clean -Ddetail
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:help (default-cli) @ maven_00 ---
[INFO] org.apache.maven.plugins:maven-clean-plugin:2.5

Maven Clean Plugin
  The Maven Clean Plugin is a plugin that removes files generated at build-time
  in a project's directory.

clean:clean
  Goal which cleans the build.
  This attempts to clean a project's working directory of the files that were
  generated at build-time. By default, it discovers and deletes the directories
  configured in project.build.directory, project.build.outputDirectory,
  project.build.testOutputDirectory, and project.reporting.outputDirectory.

  Files outside the default may also be included in the deletion by configuring
  the filesets tag.

  Available parameters:

    excludeDefaultDirectories (Default: false)
      Disables the deletion of the default output directories configured for a
      project. If set to true, only the files/directories selected via the
      parameter filesets will be deleted.
      Expression: ${clean.excludeDefaultDirectories}

    failOnError (Default: true)
      Indicates whether the build will continue even if there are clean errors.
      Expression: ${maven.clean.failOnError}

    filesets
      The list of file sets to delete, in addition to the default directories.
      For example:
      <filesets>
        <fileset>
          <directory>src/main/generated</directory>
          <followSymlinks>false</followSymlinks>
          <useDefaultExcludes>true</useDefaultExcludes>
          <includes>
            <include>*.java</include>
          </includes>
          <excludes>
            <exclude>Template*</exclude>
          </excludes>
        </fileset>
      </filesets>

    followSymLinks (Default: false)
      Sets whether the plugin should follow symbolic links while deleting files
      from the default output directories of the project. Not following symlinks
      requires more IO operations and heap memory, regardless whether symlinks
      are actually present. So projects with a huge output directory that
      knowingly does not contain symlinks can improve performance by setting
      this parameter to true.
      Expression: ${clean.followSymLinks}

    retryOnError (Default: true)
      Indicates whether the plugin should undertake additional attempts (after a
      short delay) to delete a file if the first attempt failed. This is meant
      to help deleting files that are temporarily locked by third-party tools
      like virus scanners or search indexing.
      Expression: ${maven.clean.retryOnError}

    skip (Default: false)
      Disables the plugin execution.
      Expression: ${clean.skip}

    verbose
      Sets whether the plugin runs in verbose mode. As of plugin version 2.3,
      the default value is derived from Maven's global debug flag (compare
      command line switch -X).
      Expression: ${clean.verbose}


[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.213 s
[INFO] Finished at: 2024-12-07T10:48:27+08:00
[INFO] ------------------------------------------------------------------------

可以看到,maven-clean-plugin 的 clean 目标有丰富的参数。

我们在自定义插件时也可以为 Mojo 类指定参数,以丰富插件的功能。

实现

例如,我们在 timer-maven-plugin 插件的 timer 目标类中定义如下属性:

Java 复制代码
/**
 * 时间提醒器
 *
 **/
@Mojo(name = "timer", defaultPhase = LifecyclePhase.VALIDATE)
public class TimerMojo extends AbstractMojo {

    /**
     * timeType = dateTime,则控制台显式日期时间
     * timeType = date,则控制台只显示日期
     */
    @Parameter(property = "timeType", defaultValue = "dateTime")
    private String timeType;

    public void execute() throws MojoExecutionException, MojoFailureException {
        if ("dateTime".equals(timeType)) {
            this.getLog().info("现在是北京时间:" + LocalDateTime.now());
        } else if ("date".equals(timeType)) {
            this.getLog().info("现在是:" + LocalDate.now());
        } else {
            this.getLog().info("现在是北京时间:" + LocalDateTime.now());
        }
    }
}

演示:同上,已经将 timer 目标绑定到 validate 阶段

(1) 执行命令mvn validate -DtimeType=date,结果如下

Shell 复制代码
(base) PS C:\...\maven_00> mvn validate -DtimeType=date
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- timer-maven-plugin:1.0-SNAPSHOT:timer (default-timer) @ maven_00 ---
[INFO] 现在是:2024-12-07
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.214 s
[INFO] Finished at: 2024-12-07T11:04:07+08:00
[INFO] ------------------------------------------------------------------------

(2) 执行命令mvn validate -DtimeType=date,结果如下

Shell 复制代码
(base) PS C:\...\maven_00> mvn validate -DtimeType=dateTime
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< cn.myphoenix:maven_00 >------------------------
[INFO] Building maven_00 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- timer-maven-plugin:1.0-SNAPSHOT:timer (default-timer) @ maven_00 ---
[INFO] 现在是北京时间:2024-12-07T11:07:02.601
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.189 s
[INFO] Finished at: 2024-12-07T11:07:02+08:00
[INFO] ------------------------------------------------------------------------

如上所示,通过在命令行中给属性 timeType 赋不同的值,可以执行不同的逻辑。

因此,在开发插件时,我们通常也会给目标 Mojo 设置属性值。

相关推荐
Minyy111 小时前
MAVEN--Maven的生命周期,pom.xml详解,Maven的高级特性(模块化、聚合、依赖管理)
xml·java·tomcat·maven
岁岁岁平安3 小时前
Maven学习(依赖版本维护、依赖传递、解决Maven依赖冲突的3种方式)
xml·java·学习·maven·pom·依赖冲突问题·依赖传递
哆啦 AI 梦3 小时前
【Maven】生命周期和插件详解
maven·生命周期·插件·插件目标
xuTao6673 小时前
Maven常用插件清单
maven
IT机器猫3 小时前
Maven完整技术汇总
java·maven·ssm
恩爸编程3 小时前
Maven 依赖传递:项目依赖的神奇魔法
maven·maven多模块·maven开发·maven多模块开发·maven依赖传递·maven依赖传递使用
KEEPMA3 小时前
SpringBoot左脚进门之Maven管理家
spring boot·后端·maven
恩爸编程3 小时前
Maven 统一版本:项目依赖管理的智慧之选
maven·maven统一版本·maven开发·maven多模块开发·maven统一版本开发·maven java·maven spring
WalkerShen6 小时前
使用maven的方式创建Springboot项目
java·spring boot·maven