Maven插件

Maven是一款基于插件作业的构建工具,它自身内置了非常多我们平常开发所需要的插件。如清理资源插件maven-clean-plugin,编译插件maven-compiler-plugin,打包插件maven-jar-plugin等。在工作中,我们也可以开发自己的插件,帮助我们提高开发效率

下方以开发一个统计目录下所有文件的内容行数的插件为例

创建Maven插件项目

使用archetypemaven-archetype-mojo创建一个Maven项目(对应的groupid为org.apache.maven.archetypes)

项目名最好使用name-maven-plugin,这样后续可以直接使用name:goal来执行插件目标

如下图,IDEA创建了一个count-maven-plugin项目

http://blog-image-creasylai.oss-cn-shenzhen.aliyuncs.com/blog.images/img/2022/07/article01/01.png

修改POM文件

IDEA自动创建的项目中,maven-plugin-api版本是2.0,太低了。我的Maven版本是3.6.3,所以这里我也把maven-plugin-api版本改成3.6.3

同时,我们加入maven-plugin-annotations依赖,这样开发时可以使用maven注解。同时,我们修改项目的JDK版本为1.8。最终的pom.xml文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<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.creasy.maven.plugins</groupId>
<artifactId>count-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>1.0-SNAPSHOT</version>
<name>count-maven-plugin Maven Mojo</name>
<url>http://maven.apache.org</url>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- dependencies to annotations -->
<!-- 没有3.6.3版本,我们使用3.6.2版本 -->
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.2</version>
<scope>provided</scope> <!-- annotations are not used at runtime because @Retention(value=CLASS), they are needed only to build the plugin -->
</dependency>
</dependencies>
</project>

添加goal对应的类

项目默认创建了一个MyMojo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.creasy.maven.plugins;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
* Goal which touches a timestamp file.
*
* @goal touch
*
* @phase process-sources
*/
public class MyMojo
extends AbstractMojo
{
/**
* Location of the file.
* @parameter expression="${project.build.directory}"
* @required
*/
private File outputDirectory;

public void execute()
throws MojoExecutionException
{
File f = outputDirectory;

if ( !f.exists() )
{
f.mkdirs();
}

File touch = new File( f, "touch.txt" );

FileWriter w = null;
try
{
w = new FileWriter( touch );

w.write( "touch.txt" );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error creating file " + touch, e );
}
finally
{
if ( w != null )
{
try
{
w.close();
}
catch ( IOException e )
{
// ignore
}
}
}
}
}

这个类很简单,就是在outputDirectory(对应目录为${project.build.directory},也就是常见的maven项目的target目录)目录下创建一个touch.txt文件,文件内容为touch.txt

我们参考MyMojo创建一个CountMojo类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package com.creasy.maven.plugins;

import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Mojo(name = "count",//对应插件的goal
defaultPhase = LifecyclePhase.COMPILE,//绑定Maven的生命周期的默认值
requiresProject = true,
threadSafe = true)
public class CountMojo extends AbstractMojo {

@Parameter(defaultValue = "${project.build.sourceDirectory}")
private File sourceDirectory;

@Parameter(defaultValue = "${project.build.testSourceDirectory}")
private File testSourceDirectory;

@Parameter(defaultValue = "${project.resources}")
private List<Resource> resources;

@Parameter(defaultValue = "${project.testResources}")
private List<Resource> testResources;

public void execute() throws MojoExecutionException {
try {
countLine(sourceDirectory);
countLine(testSourceDirectory);
for (Resource resource : resources) {
countLine(new File(resource.getDirectory()));
}
for (Resource testResource : testResources) {
countLine(new File(testResource.getDirectory()));
}
} catch (IOException e) {
throw new MojoExecutionException("Unable to count line!", e);
}
}

private void countLine(File dir) throws IOException {
if( dir.exists() ){
List<File> files = getFileByDir(dir);
long line = 0;
for (File file : files) {
line += countFile(file);
}
getLog().info(String.format("Directory:%s, lines:%s", dir.getPath(), line));
}
}

private List<File> getFileByDir(File dir) {
List<File> retList = new ArrayList<>();
for (File file : Objects.requireNonNull(dir.listFiles())) {
if (file.isDirectory()) {
retList.addAll(getFileByDir(file));
} else {
retList.add(file);
}
}
return retList;
}

private long countFile(File f) throws IOException {
long retValue = 0;
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(f))) {
while (null != bufferedReader.readLine()) {
retValue++;
}
}
return retValue;
}
}

这个类还是比较简单的,有几点内容说明下

  • @Parameter(defaultValue = "${project.build.sourceDirectory}")

类中的变量可以通过@Parameter注解,定义使用插件时可以传参,如果不传则默认使用项目的${project.build.sourceDirectory}属性。project.build.sourceDirectory这个属性其实是在super POM中定义的,具体可以使用的变量参考这里

  • 类必须继承AbstractMojo,实现execute接口
  • 需要使用@Mojo注解的name属性定义goal

以上,执行mvn clean install,即可把项目安装到本地仓库

使用插件

其他项目要使用插件,只需要在pom文件中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<build>
<plugins>
<plugin>
<groupId>com.creasy.maven.plugins</groupId>
<artifactId>count-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>count</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

因为count默认绑定了compile生命周期,所以这里至配置了插件的goal

执行mvn clean compile,如下,插件输出了每个资源目录下所有文件的内容行数

http://blog-image-creasylai.oss-cn-shenzhen.aliyuncs.com/blog.images/img/2022/07/article01/02.png

参考文档:

https://maven.apache.org/guides/plugin/guide-java-plugin-development.html

https://maven.apache.org/pom.html