MAVEN专题之十、设计你自己的maven插件【高手必备】

maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能。

这是maven系列第10篇。

整个maven系列的内容前后是有依赖的,如果之前没有接触过maven,建议从第一篇看起,本文尾部有maven完整系列的连接。

Maven默认提供了很多插件,功能也非常强大,但是如果我们想自己开发一些插件,比如自定义一款自动打包并且发布到服务器然后重启服务器的插件;或者定义一款插件自动打包自动运行打包好的构件。各种好玩的东西只要你能想到,都可以通过maven插件去完成,不过我们需要先了解如何自定义maven插件。

必备知识

  1. Maven系列第6篇:生命周期和插件详解,高手必备!

本篇环境

  1. jdk1.8

  2. maven3.6.2

  3. idea

本章内容

  1. 自定义插件详细步骤

  2. 自定义插件参数的使用

  3. 自定义插件前缀的使用

  4. 手动实现打包之后自动运行的插件

自定义插件详细步骤

maven中的插件是有很多目标(goal)组成的,开发插件,实际上就是去编写插件中目标的具体代码。每个目标对应一个java类,这个类在maven中叫做MOJO,maven提供了一个Mojo的接口,我们开发插件也就是去实现这个接口的方法,这个接口是:

org.apache.maven.plugin.Mojo

接口有3个方法:

  1. void execute() throws MojoExecutionException, MojoFailureException;
  2. void setLog( Log log );
  3. Log getLog();
  • execute:这个方法比较重要,目标的主要代码就在这个方法中实现,当使用mvn命令调用插件的目标的时候,最后具体调用的就是这个方法。

  • setLog:注入一个标准的Maven日志记录器,允许这个Mojo向用户传递事件和反馈

  • getLog:获取注入的日志记录器

说一下上面这个Log,这是一日志接口,里面定义了很多方法,主要用户向交互者输出日志,比如我们运行mvn clean,会输出很多提示信息,这些输出的信息就是通过Log来输出的。

Mojo接口有个默认的抽象类:

org.apache.maven.plugin.AbstractMojo

这个类中把Mojo接口中的setLoggetLog实现了,而execute方法没有实现,交给继承者去实现,这个类中Log默认可以向控制台输出日志信息,maven中自带的插件都继承这个类,一般情况下我们开发插件目标可以直接继承这个类,然后实现execute方法就可以了。

实现一个插件的具体步骤

1、 创建一个maven构件,这个构件的packaging比较特殊,必须为maven-plugin,表示这个构件是一个插件类型,如下:

pom.xml中的packageing元素必须如下值:

<packaging>maven-plugin</packaging>
2、导入maven插件依赖:
  1. <dependency>
  2.     <groupId>org.apache.maven</groupId>
  3.     <artifactId>maven-plugin-api</artifactId>
  4.     <version>3.0</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.apache.maven.plugin-tools</groupId>
  8.     <artifactId>maven-plugin-annotations</artifactId>
  9.     <version>3.4</version>
  10.     <scope>provided</scope>
  11. </dependency>
3、创建一个目标类,需要继承org.apache.maven.plugin.AbstractMojo
4、目标类中添加注解@Mojo注解:
@org.apache.maven.plugins.annotations.Mojo(name="目标名称")

注意@Mojo注解用来标注这个类是一个目标类,maven对插件进行构建的时候会根据这个注解来找到这个插件的目标,这个注解中还有其他参数,后面在详细介绍。

5、在目标类的execute方法中实现具体的逻辑
6、安装插件到本地仓库:插件的pom.xml所在目录执行下面命令
mvn clean install

或者可以部署到私服仓库,部署方式和其他构件的方式一样,这个具体去看前面文章的私服的文章。

7、让使用者去使用插件

案例1

下面我们来实现我们第一个插件,插件构件信息:

  1. <groupId>com.javacode2018</groupId>
  2. <artifactId>demo1-maven-plugin</artifactId>
  3. <version>1.0-SNAPSHOT</version>
  4. <packaging>maven-plugin</packaging>

创建一个目标类demo1,调用这个目标的时候,希望他能够输出:

hello my first maven plugin!
创建一个maven项目

打开idea,点击File->New->Project,如下图:

选择Maven,如下图:

点击上图中的Next,如下图,输入项目坐标信息:

点击上图中的Next,如下图,输入Project namemaven-chat10

点击上图中的Finish,完成创建,如下图:

配置一下idea的maven环境,点击File->Settings,如下图:

删除下面2个无用的文件夹:

创建插件模块`demo1-maven-plugin`

这次用idea创建一个插件模块demo1-maven-plugin,具体过程如下。

在刚才的maven-chat10项目窗口中,点击File->Project Structure,如下图:

也可以使用快捷键Ctrl+Alt+Shift+S打开

选择上图找你的Modules,如下图:

点击+,如下图:

选择上图中的New Module,如下图:

选择上图左侧的Maven,如下图:

点击上图中的Next,如下图:

Add as module to设置为maven-chat10,如下图:

上图中输入坐标信息,如下图:

点击上图中的Next,默认如下图:

修改上图中Module namedemo1-maven-plugin,如下图:

点击上图的Finish,如下图:

点击上图中的OK按钮,完成创建工作,目前项目结构如下图:

设置demo1-maven-plugin/pom.xml中packaging的值为maven-plugin,如下
<packaging>maven-plugin</packaging>
demo1-maven-plugin/pom.xml引入插件需要的依赖
  1. <dependency>
  2.     <groupId>org.apache.maven</groupId>
  3.     <artifactId>maven-plugin-api</artifactId>
  4.     <version>3.0</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.apache.maven.plugin-tools</groupId>
  8.     <artifactId>maven-plugin-annotations</artifactId>
  9.     <version>3.4</version>
  10.     <scope>provided</scope>
  11. </dependency>

最后demo1-maven-plugin/pom.xml内容如下

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <modelVersion>4.0.0</modelVersion>
  6.     <groupId>com.javacode2018</groupId>
  7.     <artifactId>demo1-maven-plugin</artifactId>
  8.     <version>1.0-SNAPSHOT</version>
  9.     <!-- 插件必须为maven-plugin这个类型 -->
  10.     <packaging>maven-plugin</packaging>
  11.     <properties>
  12.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13.         <!-- 配置maven编译的时候采用的编译器版本 -->
  14.         <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
  15.         <!-- 指定源代码是什么版本的,如果源码和这个版本不符将报错,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-source参数 -->
  16.         <maven.compiler.source>1.8</maven.compiler.source>
  17.         <!-- 该命令用于指定生成的class文件将保证和哪个版本的虚拟机进行兼容,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-target参数 -->
  18.         <maven.compiler.target>1.8</maven.compiler.target>
  19.     </properties>
  20.     <dependencies>
  21.         <!-- maven插件依赖 start -->
  22.         <dependency>
  23.             <groupId>org.apache.maven</groupId>
  24.             <artifactId>maven-plugin-api</artifactId>
  25.             <version>3.0</version>
  26.         </dependency>
  27.         <dependency>
  28.             <groupId>org.apache.maven.plugin-tools</groupId>
  29.             <artifactId>maven-plugin-annotations</artifactId>
  30.             <version>3.4</version>
  31.             <scope>provided</scope>
  32.         </dependency>
  33.         <!-- maven插件依赖 end -->
  34.     </dependencies>
  35.     <build>
  36.         <plugins>
  37.             <plugin>
  38.                 <groupId>org.apache.maven.plugins</groupId>
  39.                 <artifactId>maven-plugin-plugin</artifactId>
  40.                 <version>3.4</version>
  41.             </plugin>
  42.         </plugins>
  43.     </build>
  44. </project>
创建目标类

demo-maven-plugin中创建的目标类com.javacode2018.Demo1Mojo,需要继承org.apache.maven.plugin.AbstractMojo,需要实现@Mojo注解,如下:

  1. package com.javacode2018;
  2. import org.apache.maven.plugin.AbstractMojo;
  3. import org.apache.maven.plugin.MojoExecutionException;
  4. import org.apache.maven.plugin.MojoFailureException;
  5. import org.apache.maven.plugins.annotations.Mojo;
  6. /**
  7.  * 工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!喜欢的请关注公众号:路人甲Java
  8.  */
  9. @Mojo(name = "demo1")
  10. public class Demo1Mojo extends AbstractMojo {
  11.     public void execute() throws MojoExecutionException, MojoFailureException {
  12.     }
  13. }

注意上面注解@Mojo(name = "demo1")name使用来标注目标的名称为demo1

实现目标类的execute方法

我们在execute方法中输出一句话

this.getLog().info("hello my first maven plugin!");

目前execute方法代码如下:

  1. public void execute() throws MojoExecutionException, MojoFailureException {
  2.     this.getLog().info("hello my first maven plugin!");
  3. }
安装插件到本地仓库

maven-chat10/pom.xml目录执行下面命令:

mvn clean install -pl :demo1-maven-plugin

注意上面命令和在demo1-maven-plugin/pom中执行mvn clean install效果是一样的,只是这个地方使用了maven裁剪的功能,对这块命令不熟悉的可以看:Maven系列第8篇:大型Maven项目,快速按需任意构建,必备神技能!

上面命令效果如下:

  1. D:\code\IdeaProjects\maven-chat10>mvn clean install -pl :demo1-maven-plugin
  2. [INFO] Scanning for projects...
  3. [INFO]
  4. [INFO] ----------------< com.javacode2018:demo1-maven-plugin >-----------------
  5. [INFO] Building demo1-maven-plugin 1.0-SNAPSHOT
  6. [INFO] ----------------------------[ maven-plugin ]----------------------------
  7. [INFO]
  8. [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ demo1-maven-plugin ---
  9. [INFO] Deleting D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\target
  10. [INFO]
  11. [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ demo1-maven-plugin ---
  12. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  13. [INFO] Copying 0 resource
  14. [INFO]
  15. [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ demo1-maven-plugin ---
  16. [INFO] Changes detected - recompiling the module!
  17. [INFO] Compiling 1 source file to D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\target\classes
  18. [INFO]
  19. [INFO] --- maven-plugin-plugin:3.4:descriptor (default-descriptor) @ demo1-maven-plugin ---
  20. [INFO] Using 'UTF-8' encoding to read mojo metadata.
  21. [INFO] Mojo extractor with id: java-javadoc found 0 mojo descriptors.
  22. [INFO] Mojo extractor with id: java-annotations found 1 mojo descriptors.
  23. [INFO]
  24. [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ demo1-maven-plugin ---
  25. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  26. [INFO] skip non existing resourceDirectory D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\src\test\resources
  27. [INFO]
  28. [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ demo1-maven-plugin ---
  29. [INFO] Nothing to compile - all classes are up to date
  30. [INFO]
  31. [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ demo1-maven-plugin ---
  32. [INFO] No tests to run.
  33. [INFO]
  34. [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ demo1-maven-plugin ---
  35. [INFO] Building jar: D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\target\demo1-maven-plugin-1.0-SNAPSHOT.jar
  36. [INFO]
  37. [INFO] --- maven-plugin-plugin:3.4:addPluginArtifactMetadata (default-addPluginArtifactMetadata) @ demo1-maven-plugin ---
  38. [INFO]
  39. [INFO] --- maven-install-plugin:2.4:install (default-install) @ demo1-maven-plugin ---
  40. [INFO] Installing D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\target\demo1-maven-plugin-1.0-SNAPSHOT.jar to C:\Users\Think\.m2\repository\com\javacode2018\demo1-maven-plugin\1.0-SNAPSHOT\demo1-maven-plugin-1.0-SNAPSHOT.jar
  41. [INFO] Installing D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\pom.xml to C:\Users\Think\.m2\repository\com\javacode2018\demo1-maven-plugin\1.0-SNAPSHOT\demo1-maven-plugin-1.0-SNAPSHOT.pom
  42. [INFO] ------------------------------------------------------------------------
  43. [INFO] BUILD SUCCESS
  44. [INFO] ------------------------------------------------------------------------
  45. [INFO] Total time:  5.402 s
  46. [INFO] Finished at: 2019-11-26T15:21:26+08:00
  47. [INFO] ------------------------------------------------------------------------
验证插件,调用插件的demo1目标看效果

maven-chat10/pom.xml所在目录执行:

mvn com.javacode2018:demo1-maven-plugin:demo1

效果如下:

  1. D:\code\IdeaProjects\maven-chat10>mvn com.javacode2018:demo1-maven-plugin:demo1
  2. [INFO] Scanning for projects...
  3. [INFO] ------------------------------------------------------------------------
  4. [INFO] Reactor Build Order:
  5. [INFO]
  6. [INFO] demo1-maven-plugin                                        [maven-plugin]
  7. [INFO] maven-chat10                                                       [pom]
  8. [INFO]
  9. [INFO] ----------------< com.javacode2018:demo1-maven-plugin >-----------------
  10. [INFO] Building demo1-maven-plugin 1.0-SNAPSHOT                           [1/2]
  11. [INFO] ----------------------------[ maven-plugin ]----------------------------
  12. [INFO]
  13. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:demo1 (default-cli) @ demo1-maven-plugin ---
  14. [INFO] hello my first maven plugin!
  15. [INFO]
  16. [INFO] -------------------< com.javacode2018:maven-chat10 >--------------------
  17. [INFO] Building maven-chat10 1.0-SNAPSHOT                                 [2/2]
  18. [INFO] --------------------------------[ pom ]---------------------------------
  19. [INFO]
  20. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:demo1 (default-cli) @ maven-chat10 ---
  21. [INFO] hello my first maven plugin!
  22. [INFO] ------------------------------------------------------------------------
  23. [INFO] Reactor Summary for maven-chat10 1.0-SNAPSHOT:
  24. [INFO]
  25. [INFO] demo1-maven-plugin ................................. SUCCESS [  0.358 s]
  26. [INFO] maven-chat10 ....................................... SUCCESS [  0.042 s]
  27. [INFO] ------------------------------------------------------------------------
  28. [INFO] BUILD SUCCESS
  29. [INFO] ------------------------------------------------------------------------
  30. [INFO] Total time:  0.656 s
  31. [INFO] Finished at: 2019-11-26T13:49:30+08:00

上面输出的东西比较多,我们主要看一下有这样的一句输出,如下:

[INFO] hello my first maven plugin!

上面这个输出就是我们在execute方法中输出的内容。

目标中参数的使用

上面我们介绍了开发一个插件目标详细的实现过程,然后写了一个简单的案例,比较简单。不过自定义的Mojo如果没有参数,那么这个Mojo基本上也实现不了什么复杂的功能,下面我们来看一下Mojo中如何使用参数。

需要先在mojo中定义参数

定义参数就像在mojo中创建一个实例变量并添加适当的注释一样简单。下面列出了一个简单mojo的参数示例:

  1. /**
  2.  * 要显示的问候语。
  3.  */
  4. @Parameter( property = "sayhi.greeting", defaultValue = "Hello World!" )
  5. private String greeting;

@Parameter注解之前的部分是参数的描述,这个注解将变量标识为mojo参数。注解的defaultValue参数定义变量的默认值,此值maven的属性值,例如“${project.version}”(更多信息可以看上一篇文章中的 target="_blank">maven属性部分),property参数可用于通过引用用户通过-D选项设置的系统属性,即通过从命令行配置mojo参数,如mvn ... -Dsayhi.greeting=路人甲Java可以将路人甲Java的值传递给greeting参数,这个注解还有几个属性大家有兴趣的可以自己去研究一下。

在pom.xml配置参数的值

  1. <plugin>
  2.   <groupId>com.javacode2018</groupId>
  3.   <artifactId>demo1-maven-plugin</artifactId>
  4.   <version>1.0-SNAPSHOT</version>
  5.   <configuration>
  6.     <greeting>欢迎您和【路人甲Java】一起学习Maven技术!</greeting>
  7.   </configuration>
  8. </plugin>

上面设置的是一个string类型的greeting参数的值,还有其他很多类型定义以及使用,我们也来看一下。

Boolean参数

  1. /**
  2. * My boolean.
  3. */
  4. @Parameter
  5. private boolean myBoolean;
<myBoolean>true</myBoolean>

数字类型参数

数字类型包含:byte, Byte, int, Integer, long, Long, short, Short,读取配置时,XML文件中的文本将使用适当类的integer.parseInt()或valueOf()方法转换为整数值,这意味着字符串必须是有效的十进制整数值,仅由数字0到9组成,前面有一个可选的-表示负值。例子:

  1. /**
  2. * My Integer.
  3. */
  4. @Parameter
  5. private Integer myInteger;
<myInteger>10</myInteger>

File类型参数

读取配置时,XML文件中的文本用作所需文件或目录的路径。如果路径是相对的(不是以/或C:之类的驱动器号开头),则路径是相对于包含POM的目录的。例子:

  1. /**
  2. * My File.
  3. */
  4. @Parameter
  5. private File myFile;
<myFile>c:\temp</myFile>

枚举类型参数

  1. public enum Color {
  2.       GREEN,
  3.       RED,
  4.       BLUE
  5. }
  6. /**
  7. * My Enum
  8. */
  9. @Parameter
  10. private Color myColor;
<myColor>GREEN</myColor>

数组类型参数

  1. /**
  2. * My Array.
  3. */
  4. @Parameter
  5. private String[] myArray;
  1. <myArray>
  2.   <param>value1</param>
  3.   <param>value2</param>
  4. </myArray>

Collections类型参数

  1. /**
  2. * My List.
  3. */
  4. @Parameter
  5. private List myList;
  1. <myList>
  2.   <param>value1</param>
  3.   <param>value2</param>
  4. </myList>

Maps类型参数

  1. /**
  2. * My Map.
  3. */
  4. @Parameter
  5. private Map myMap;
  1. <myMap>
  2.   <key1>value1</key1>
  3.   <key2>value2</key2>
  4. </myMap>

Properties类型参数

java.util.Properties的类型

  1. /**
  2. * My Properties.
  3. */
  4. @Parameter
  5. private Properties myProperties;
  1. <myProperties>
  2.   <property>
  3.     <name>propertyName1</name>
  4.     <value>propertyValue1</value>
  5.   <property>
  6.   <property>
  7.     <name>propertyName2</name>
  8.     <value>propertyValue2</value>
  9.   <property>
  10. </myProperties>

自定义类型参数

  1. /**
  2. * My Object.
  3. */
  4. @Parameter
  5. private MyObject myObject;
  1. <myObject>
  2.   <myField>test</myField>
  3. </myObject>

案例2

修改案例代码

我们将上面各种类型的参数都放到Demo1Mojo中,Demo1Mojo类如下:

  1. package com.javacode2018;
  2. import org.apache.maven.plugin.AbstractMojo;
  3. import org.apache.maven.plugin.MojoExecutionException;
  4. import org.apache.maven.plugin.MojoFailureException;
  5. import org.apache.maven.plugins.annotations.Mojo;
  6. import org.apache.maven.plugins.annotations.Parameter;
  7. import java.io.File;
  8. import java.lang.reflect.Field;
  9. import java.util.Arrays;
  10. import java.util.List;
  11. import java.util.Map;
  12. import java.util.Properties;
  13. /**
  14.  * 工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!喜欢的请关注公众号:路人甲Java
  15.  */
  16. @Mojo(name = "demo1")
  17. public class Demo1Mojo extends AbstractMojo {
  18.     /**
  19.      * 要显示的问候语。
  20.      */
  21.     @Parameter(property = "sayhi.greeting", defaultValue = "Hello World!")
  22.     private String greeting;
  23.     /**
  24.      * My boolean.
  25.      */
  26.     @Parameter
  27.     private boolean myBoolean;
  28.     /**
  29.      * My Integer.
  30.      */
  31.     @Parameter
  32.     private Integer myInteger;
  33.     /**
  34.      * My File.
  35.      */
  36.     @Parameter
  37.     private File myFile;
  38.     public enum Color {
  39.         GREEN,
  40.         RED,
  41.         BLUE
  42.     }
  43.     /**
  44.      * My Enum
  45.      */
  46.     @Parameter
  47.     private Color myColor;
  48.     /**
  49.      * My Array.
  50.      */
  51.     @Parameter
  52.     private String[] myArray;
  53.     /**
  54.      * My List.
  55.      */
  56.     @Parameter
  57.     private List myList;
  58.     /**
  59.      * My Map.
  60.      */
  61.     @Parameter
  62.     private Map myMap;
  63.     /**
  64.      * My Properties.
  65.      */
  66.     @Parameter
  67.     private Properties myProperties;
  68.     public static class Person {
  69.         private String name;
  70.         private int age;
  71.         public String getName() {
  72.             return name;
  73.         }
  74.         public void setName(String name) {
  75.             this.name = name;
  76.         }
  77.         public int getAge() {
  78.             return age;
  79.         }
  80.         public void setAge(int age) {
  81.             this.age = age;
  82.         }
  83.         @Override
  84.         public String toString() {
  85.             return "Person{" +
  86.                     "name='" + name + '\'' +
  87.                     ", age=" + age +
  88.                     '}';
  89.         }
  90.     }
  91.     @Parameter
  92.     private Person person;
  93.     public void execute() throws MojoExecutionException, MojoFailureException {
  94.         this.getLog().info("hello my first maven plugin!");
  95.         Field[] declaredFields = Demo1Mojo.class.getDeclaredFields();
  96.         Arrays.stream(declaredFields).forEach(f -> {
  97.             if (f.isAccessible()) {
  98.                 f.setAccessible(true);
  99.             }
  100.             try {
  101.                 this.getLog().info(f.getName() + ":" + f.get(this));
  102.             } catch (IllegalAccessException e) {
  103.                 this.getLog().warn(e);
  104.             }
  105.         });
  106.     }
  107. }
将`demo1-maven-plugin`安装到本地仓库

maven-chat10/pom.xml所在目录运行:

mvn clean install -pl :demo1-maven-plugin
创建测试模块`demo1-maven-plugin-test`

使用idea创建,过程和demo1-maven-plugin过程类似,可以直接参考,创建好了,如下:

修改demo1-mavein-plugin-test/pom.xml文件,加入下面内容:

  1. <build>
  2.     <plugins>
  3.         <plugin>
  4.             <groupId>com.javacode2018</groupId>
  5.             <artifactId>demo1-maven-plugin</artifactId>
  6.             <version>1.0-SNAPSHOT</version>
  7.             <executions>
  8.                 <execution>
  9.                     <id>demo1 plugin test</id>
  10.                     <phase>pre-clean</phase>
  11.                     <goals>
  12.                         <goal>demo1</goal>
  13.                     </goals>
  14.                     <configuration>
  15.                         <myBoolean>true</myBoolean>
  16.                         <myInteger>30</myInteger>
  17.                         <myFile>${project.basedir}</myFile>
  18.                         <myColor>BLUE</myColor>
  19.                         <myArray>
  20.                             <array>maven</array>
  21.                             <array>spring</array>
  22.                             <array>mybatis</array>
  23.                             <array>springboot</array>
  24.                             <array>springcloud</array>
  25.                         </myArray>
  26.                         <myList>
  27.                             <list>30</list>
  28.                             <list>35</list>
  29.                         </myList>
  30.                         <myMap>
  31.                             <name>路人甲Java</name>
  32.                             <age>30</age>
  33.                         </myMap>
  34.                         <myProperties>
  35.                             <property>
  36.                                 <name>name</name>
  37.                                 <value>javacode2018</value>
  38.                             </property>
  39.                             <property>
  40.                                 <name>age</name>
  41.                                 <value>30</value>
  42.                             </property>
  43.                         </myProperties>
  44.                         <person>
  45.                             <name>路人甲Java</name>
  46.                             <age>32</age>
  47.                         </person>
  48.                     </configuration>
  49.                 </execution>
  50.             </executions>
  51.         </plugin>
  52.     </plugins>
  53. </build>

上面是将生命周期的pre-clean阶段绑定插件demo1-maven-plugindemo1目标,并且设置了demo1目标所需要的所有参数的值。

验证效果

maven-chat10/pom.xml所在目录执行:

  1. D:\code\IdeaProjects\maven-chat10>mvn pre-clean -pl :demo1-maven-plugin-test -Dsayhi.greeting="欢迎和【路人甲Java】一起学习Maven!"
  2. [INFO] Scanning for projects...
  3. [INFO]
  4. [INFO] --------------< com.javacode2018:demo1-maven-plugin-test >--------------
  5. [INFO] Building demo1-maven-plugin-test 1.0-SNAPSHOT
  6. [INFO] --------------------------------[ jar ]---------------------------------
  7. [INFO]
  8. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:demo1 (demo1 plugin test) @ demo1-maven-plugin-test ---
  9. [INFO] hello my first maven plugin!
  10. [INFO] greeting:欢迎和【路人甲Java】一起学习Maven!
  11. [INFO] myBoolean:true
  12. [INFO] myInteger:30
  13. [INFO] myFile:D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-test
  14. [INFO] myColor:BLUE
  15. [INFO] myArray:[Ljava.lang.String;@7bf9b098
  16. [INFO] myList:[3035]
  17. [INFO] myMap:{age=30, name=路人甲Java}
  18. [INFO] myProperties:{age=30, name=javacode2018}
  19. [INFO] person:Person{name='路人甲Java', age=32}
  20. [INFO] ------------------------------------------------------------------------
  21. [INFO] BUILD SUCCESS
  22. [INFO] ------------------------------------------------------------------------
  23. [INFO] Total time:  0.517 s
  24. [INFO] Finished at: 2019-11-26T15:42:53+08:00
  25. [INFO] ------------------------------------------------------------------------

插件前缀

在案例1中,我们使用下面命令调用的插件:

mvn com.javacode2018:demo1-maven-plugin:demo1

这种是采用下面这种格式:

mvn 插件groupId:插件artifactId[:插件版本]:插件目标名称

命令中插件版本是可以省略的,maven会自动找到这个插件最新的版本运行,不过最好我们不要省略版本号,每个版本的插件功能可能不一样,为了保证任何情况下运行效果的一致性,强烈建议指定版本号。

上面执行插件需要插件的坐标信息,一长串比较麻烦,maven也为了我们使用插件方便,提供了插件前缀来帮我们解决这个问题。

自定义插件前缀的使用

设置自定义插件的artifactId

自定义插件的artifactId满足下面的格式:

xxx-maven-plugin

如果采用这种格式的maven会自动将xxx指定为插件的前缀,其他格式也可以,不过此处我们只说这种格式,这个是最常用的格式。

如我们上面的demo1-maven-plugin插件,他的前缀就是demo1

当我们配置了插件前缀,可以插件前缀来调用插件的目标了,命令如下:

mvn 插件前缀:插件目标

maven是如何通过插件前缀找到具体的插件的呢?

maven默认会在仓库"org.apache.maven.plugins" 和 "org.codehaus.mojo"2个位置查找插件,比如:

mvn clean:help

这个是调用maven-clean-plugin插件的help目标,maven-clean-plugin的前缀就是clean,他的groupIdorg.apache.maven.plugins,所以能够直接找到。

但是我们自己定义的插件,如果也让maven能够找到,需要下面的配置。

在`~/.m2/settings.xml`中配置自定义插件组

pluginGroups中加入自定义的插件组groupId,如:

<pluginGroup>com.javacode2018</pluginGroup>

这样当我们通过前缀调用插件的时候,maven除了会在2个默认的组中查找,还会在这些自定义的插件组中找,一般情况下我们自定义的插件通常使用同样的groupId

使用插件前缀调用插件
mvn 插件前缀:插件目标

案例3

~/.m2/settings.xml中加入下面配置:

<pluginGroup>com.javacode2018</pluginGroup>

maven-chat10/pom.xml所在目录执行:

mvn demo1:demo1 -pl demo1-maven-plugin-test

效果如下:

  1. D:\code\IdeaProjects\maven-chat10>mvn demo1:demo1 -pl demo1-maven-plugin-test
  2. [INFO] Scanning for projects...
  3. [INFO]
  4. [INFO] --------------< com.javacode2018:demo1-maven-plugin-test >--------------
  5. [INFO] Building demo1-maven-plugin-test 1.0-SNAPSHOT
  6. [INFO] --------------------------------[ jar ]---------------------------------
  7. [INFO]
  8. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:demo1 (default-cli) @ demo1-maven-plugin-test ---
  9. [INFO] hello my first maven plugin!
  10. [INFO] greeting:Hello World!
  11. [INFO] myBoolean:false
  12. [INFO] myInteger:null
  13. [INFO] myFile:null
  14. [INFO] myColor:null
  15. [INFO] myArray:null
  16. [INFO] myList:null
  17. [INFO] myMap:null
  18. [INFO] myProperties:null
  19. [INFO] person:null
  20. [INFO] ------------------------------------------------------------------------
  21. [INFO] BUILD SUCCESS
  22. [INFO] ------------------------------------------------------------------------
  23. [INFO] Total time:  0.786 s
  24. [INFO] Finished at: 2019-11-26T16:10:41+08:00
  25. [INFO] ------------------------------------------------------------------------

上面直接通过插件的前缀来调用插件的功能了,是不是很爽!

手动实现打包之后自动运行的插件

实现思路

1、将目标构件打包为可以执行jar包到target目录

maven中将构件打包为可以执行的jar的插件,maven已经帮我们提供了,如下:

  1. <plugin>
  2.     <groupId>org.apache.maven.plugins</groupId>
  3.     <artifactId>maven-shade-plugin</artifactId>
  4.     <version>3.2.1</version>
  5.     <executions>
  6.         <execution>
  7.             <phase>package</phase>
  8.             <goals>
  9.                 <goal>shade</goal>
  10.             </goals>
  11.             <configuration>
  12.                 <transformers>
  13.                     <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  14.                         <mainClass>启动类完整路径</mainClass>
  15.                     </transformer>
  16.                 </transformers>
  17.             </configuration>
  18.         </execution>
  19.     </executions>
  20. </plugin>

上面使用到了maven官方提供的一个打包的插件,可以将构件打包为可以直接运行的jar包。

2、自定义一个插件,然后执行上面打包好的插件

插件中需要通过java命令调用打包好的jar包,然后运行。

具体实现如下

创建自定义目标类

demo1-maven-plugin中创建一个插件目标类,如下:

  1. package com.javacode2018;
  2. import org.apache.maven.plugin.AbstractMojo;
  3. import org.apache.maven.plugin.MojoExecutionException;
  4. import org.apache.maven.plugin.MojoFailureException;
  5. import org.apache.maven.plugins.annotations.Execute;
  6. import org.apache.maven.plugins.annotations.LifecyclePhase;
  7. import org.apache.maven.plugins.annotations.Mojo;
  8. import org.apache.maven.plugins.annotations.Parameter;
  9. import java.io.BufferedReader;
  10. import java.io.IOException;
  11. import java.io.InputStreamReader;
  12. /**
  13.  * 工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!喜欢的请关注公众号:路人甲Java
  14.  */
  15. @Mojo(name = "run", defaultPhase = LifecyclePhase.PACKAGE)
  16. @Execute(phase = LifecyclePhase.PACKAGE)
  17. public class RunMojo extends AbstractMojo {
  18.     /**
  19.      * 打包好的构件的路径
  20.      */
  21.     @Parameter(defaultValue = "${project.build.directory}\\${project.artifactId}-${project.version}.jar")
  22.     private String jarPath;
  23.     @Override
  24.     public void execute() throws MojoExecutionException, MojoFailureException {
  25.         try {
  26.             this.getLog().info("Started:" + this.jarPath);
  27.             ProcessBuilder builder = new ProcessBuilder("java""-jar", this.jarPath);
  28.             final Process process = builder.start();
  29.             new Thread(() -> {
  30.                 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
  31.                 try {
  32.                     String s;
  33.                     while ((s = reader.readLine()) != null) {
  34.                         System.out.println(s);
  35.                     }
  36.                 } catch (IOException e) {
  37.                     e.printStackTrace();
  38.                 }
  39.             }).start();
  40.             Runtime.getRuntime().addShutdownHook(new Thread() {
  41.                 @Override
  42.                 public void run() {
  43.                     RunMojo.this.getLog().info("Destroying...");
  44.                     process.destroy();
  45.                     RunMojo.this.getLog().info("Shutdown hook finished.");
  46.                 }
  47.             });
  48.             process.waitFor();
  49.             this.getLog().info("Finished.");
  50.         } catch (Exception e) {
  51.             this.getLog().warn(e);
  52.         }
  53.     }
  54. }

上面这个插件目标的名称为run

注意这个类上面多了一个注解@Execute,这个注解可以配置这个目标执行之前可以先执行的生命周期的阶段或者需要先执行的插件目标

上面配置的是phase = LifecyclePhase.PACKAGE,也就是说当我们运行上面run目标的时候,会先执行构件的package阶段,也就是先执行项目的打包阶段,打包完成之后才会执行run目标。

安装插件到本地仓库

maven-chat10/pom.xml所在目录运行:

mvn clean install -pl :demo1-maven-plugin
创建测试模块`demo1-maven-plugin-run`

使用idea创建,过程和demo1-maven-plugin过程类似,可以直接参考,创建好了,如下:

创建`com.javacode2018.Demo`类

在demo1-maven-plugin-run\src\main\java创建下面类:

  1. package com.javacode2018;
  2. import java.util.Calendar;
  3. import java.util.concurrent.TimeUnit;
  4. /**
  5.  * 工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!喜欢的请关注公众号:路人甲Java
  6.  */
  7. public class Demo1 {
  8.     public static void main(String[] args) throws InterruptedException {
  9.         for (int i = 0; i < 1000; i++) {
  10.             System.out.println(Calendar.getInstance().getTime() + ":" + i);
  11.             TimeUnit.SECONDS.sleep(1);
  12.         }
  13.     }
  14. }
修改`demo1-maven-plugin-run/pom.xml`,如下
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <modelVersion>4.0.0</modelVersion>
  6.     <groupId>com.javacode2018</groupId>
  7.     <artifactId>demo1-maven-plugin-run</artifactId>
  8.     <version>1.0-SNAPSHOT</version>
  9.     <properties>
  10.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  11.         <!-- 配置maven编译的时候采用的编译器版本 -->
  12.         <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
  13.         <!-- 指定源代码是什么版本的,如果源码和这个版本不符将报错,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-source参数 -->
  14.         <maven.compiler.source>1.8</maven.compiler.source>
  15.         <!-- 该命令用于指定生成的class文件将保证和哪个版本的虚拟机进行兼容,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-target参数 -->
  16.         <maven.compiler.target>1.8</maven.compiler.target>
  17.     </properties>
  18.     <build>
  19.         <plugins>
  20.             <plugin>
  21.                 <groupId>org.apache.maven.plugins</groupId>
  22.                 <artifactId>maven-shade-plugin</artifactId>
  23.                 <version>3.2.1</version>
  24.                 <executions>
  25.                     <execution>
  26.                         <phase>package</phase>
  27.                         <goals>
  28.                             <goal>shade</goal>
  29.                         </goals>
  30.                         <configuration>
  31.                             <transformers>
  32.                                 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  33.                                     <mainClass>com.javacode2018.Demo1</mainClass>
  34.                                 </transformer>
  35.                             </transformers>
  36.                         </configuration>
  37.                     </execution>
  38.                 </executions>
  39.             </plugin>
  40.         </plugins>
  41.     </build>
  42. </project>
验证效果见证奇迹的时刻

maven-chat10/pom.xml所在目录执行下面的命令:

mvn clean demo1:run -pl demo1-maven-plugin-run

输出如下:

  1. D:\code\IdeaProjects\maven-chat10>mvn clean demo1:run -pl demo1-maven-plugin-run
  2. [INFO] Scanning for projects...
  3. [INFO]
  4. [INFO] --------------< com.javacode2018:demo1-maven-plugin-run >---------------
  5. [INFO] Building demo1-maven-plugin-run 1.0-SNAPSHOT
  6. [INFO] --------------------------------[ jar ]---------------------------------
  7. [INFO]
  8. [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ demo1-maven-plugin-run ---
  9. [INFO] Deleting D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target
  10. [INFO]
  11. [INFO] >>> demo1-maven-plugin:1.0-SNAPSHOT:run (default-cli) > package @ demo1-maven-plugin-run >>>
  12. [INFO]
  13. [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ demo1-maven-plugin-run ---
  14. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  15. [INFO] Copying 0 resource
  16. [INFO]
  17. [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ demo1-maven-plugin-run ---
  18. [INFO] Changes detected - recompiling the module!
  19. [INFO] Compiling 1 source file to D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\classes
  20. [INFO]
  21. [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ demo1-maven-plugin-run ---
  22. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  23. [INFO] skip non existing resourceDirectory D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\src\test\resources
  24. [INFO]
  25. [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ demo1-maven-plugin-run ---
  26. [INFO] Nothing to compile - all classes are up to date
  27. [INFO]
  28. [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ demo1-maven-plugin-run ---
  29. [INFO] No tests to run.
  30. [INFO]
  31. [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ demo1-maven-plugin-run ---
  32. [INFO] Building jar: D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\demo1-maven-plugin-run-1.0-SNAPSHOT.jar
  33. [INFO]
  34. [INFO] --- maven-shade-plugin:3.2.1:shade (default) @ demo1-maven-plugin-run ---
  35. [INFO] Replacing original artifact with shaded artifact.
  36. [INFO] Replacing D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\demo1-maven-plugin-run-1.0-SNAPSHOT.jar with D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\demo1-maven-plugin-run-1.0-SNAPSHOT-shaded.jar
  37. [INFO]
  38. [INFO] <<< demo1-maven-plugin:1.0-SNAPSHOT:run (default-cli) < package @ demo1-maven-plugin-run <<<
  39. [INFO]
  40. [INFO]
  41. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:run (default-cli) @ demo1-maven-plugin-run ---
  42. [INFO] Started:D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\demo1-maven-plugin-run-1.0-SNAPSHOT.jar
  43. Tue Nov 26 17:24:47 CST 2019:0
  44. Tue Nov 26 17:24:48 CST 2019:1
  45. Tue Nov 26 17:24:49 CST 2019:2
  46. Tue Nov 26 17:24:50 CST 2019:3
  47. Tue Nov 26 17:24:51 CST 2019:4
  48. Tue Nov 26 17:24:52 CST 2019:5
  49. Tue Nov 26 17:24:53 CST 2019:6
  50. Tue Nov 26 17:24:54 CST 2019:7
  51. Tue Nov 26 17:24:55 CST 2019:8
  52. Tue Nov 26 17:24:56 CST 2019:9
  53. Tue Nov 26 17:24:57 CST 2019:10
  54. Tue Nov 26 17:24:58 CST 2019:11
  55. Tue Nov 26 17:24:59 CST 2019:12
  56. Tue Nov 26 17:25:00 CST 2019:13

是不是打包+运行很简单,一行命令就搞定了。

后面我们需要学的springboot中也是一个maven命令就可以启动springboot项目,这个原理和我们上面的类似,是spring官方他们自己开发了一款maven插件,可以直接运行springboot项目,后面学习springboot的时候,我们会详细介绍。

总结

本文的内容起到一个抛砖引玉的作用,大家如果有兴趣,可以去写很多更好的maven插件玩玩,maven默认提供了很多优秀的插件,大家可以去看他们的源码,借鉴他们的设计思路,开发出自己喜欢的插件使用,有问题的可以加我微信【itsoku】或者留言交流!

maven系列到此已经结束了,10篇如果都能够坚持看完,大家已经成为一等一的高手了。

后面将进行mybatis、springboot、springcloud系列,所有系列的目标都是让大家掌握从入门到高级开发所需要的所有技能。

Maven系列目录

  1. Maven系列:第1篇:Maven未出世前,我们那些痛苦的经历!

  2. Maven系列第2篇:安装、配置、mvn运行过程详解

  3. Maven系列第3篇:详解maven解决依赖问题

  4. Maven系列第4篇:仓库详解

  5. Maven系列第5篇:私服详解

  6. Maven系列第6篇:生命周期和插件详解,高手必备!

  7. Maven系列第7篇:聚合、继承、单继承问题详解,必备技能!

  8. Maven系列第8篇:大型Maven项目,快速按需任意构建,必备神技能!

  9. Maven系列第9篇:多环境构建,作为核心开发,这个玩不转有点说不过去!

更多好文章

  1. java高并发系列(共34篇)

  2. mysql高手系列(共27篇)

  3. 聊聊db和缓存一致性常见的实现方式

  4. 接口幂等性这么重要,它是什么?怎么实现?

感谢大家的阅读,也欢迎您把这篇文章分享给更多的朋友一起阅读!谢谢!

路人甲java

▲长按图片识别二维码关注

路人甲Java:工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!

文章知识点与官方知识档案匹配,可进一步学习相关知识
Java技能树Java概览Maven基础14061 人正在系统学习中 来源:https://itsoku.blog.csdn.net/article/details/103268188
posted @ 2022-04-22 01:19  程序员小明1024  阅读(384)  评论(0编辑  收藏  举报