概述:
通過開發一個簡單的maven插件來更深入的了解maven
maven:
maven是一個包管理和插件排程架構,所有的功能(如編譯、打包、釋出)都是由插件完成的。
maven有30個階段,這30個階段(phase)分别歸屬于3個标準的生命周期,所有的插件都需要綁定到其中一個階段執行(插件本身可以設定預設階段,pom.xml中也可以重新綁定插件的階段,最後是可以在執行mvn指令時綁定插件的階段)。編譯時調用某個階段,該階段及在該階段所屬的生命周期前的所有階段都會被執行,如,執行clean,那麼pre-clean,clean都會被執行。可以看作在maven内部有一個模闆方法,指定一個階段時,該階段的方法,以及該階段前的所有方法都會執行。
3個标準生命周期及30個階段(@See org.apache.maven.plugins.annotations.LifecyclePhase):
clean: pre-clean,clean,post-clean
build(預設的生命周期): validate,initialize,generate-sources,process-sources,generate-resources,process-resources,compile,process-classes,generate-test-sources,process-test-sources,generate-test-resources,process-test-resources,test-compile,process-test-classes,test,prepare-package,package,pre-integration-test,integration-test,post-integration-test,verify,install,deploy
site: pre-site,site,post-site,site-deploy
步驟:
1.打開指令行,執行以下指令,建立一個插件項目(該項目本身也是一個maven項目):
mvn archetype:generate -DgroupId=com.study.maven.plugins -DartifactId=line-count -Dversion=0.0.1-SNAPSHOT -DarchetypeArtifactId=maven-archetype-plugin -DinteractiveMode=false -DarchetypeCatalog=internal
其中(-D後是輸入參數):
groupId的值用于指定pom.xml中的groupId
artifactId的值用于指定pom.xml中的artifactId
version的值用于指定pom.xml中的version
其它參數照抄就行
2.編寫插件代碼
(見代碼)
3.使用插件
在要使用該插件的項目的pom.xml檔案中的<build>下<plugins>下添加如下配置:
<plugin>
<groupId>com.study.maven.plugins</groupId>
<artifactId>line-count</artifactId>
<version>0.0.1-SNAPSHOT</version>
<executions>
<execution>
<id>count</id>
<!--重新綁定插件的phase-->
<phase>install</phase>
<goals>
<goal>count</goal>
</goals>
<!--配置參數-->
<configuration>
<fileType>java</fileType>
<minSpaceNum>10</minSpaceNum>
<countRelBaseDir>./src</countRelBaseDir>
</configuration>
</execution>
</executions>
</plugin>
代碼:
配置檔案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.study.maven.plugins</groupId>
<artifactId>line-count</artifactId>
<packaging>maven-plugin</packaging>
<version>0.0.1-SNAPSHOT</version>
<!--指定使用的jdk版本-->
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<jdk>1.8</jdk>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
<name>line-count Maven Mojo</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!--引入maven插件的注解-->
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.5</version>
</dependency>
</dependencies>
</project>
檔案行數資訊FileLineInfo:
package com.study.maven.plugins;
public class FileLineInfo {
private String filePath;
private Integer lineCount;
public FileLineInfo(String filePath, Integer lineCount) {
this.filePath = filePath;
this.lineCount = lineCount;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public Integer getLineCount() {
return lineCount;
}
public void setLineCount(Integer lineCount) {
this.lineCount = lineCount;
}
}
字元串工具類MyStringUtils:
package com.study.maven.plugins;
public class MyStringUtils {
public static boolean isBlank(String str) {
return !isNotBlank(str);
}
public static boolean isNotBlank(String str) {
return str != null && !str.isEmpty() && containsText(str);
}
private static boolean containsText(CharSequence str) {
int strLen = str.length();
for (int i = 0; i < strLen; ++i) {
if (!Character.isWhitespace(str.charAt(i))) {
return true;
}
}
return false;
}
}
插件類MyMojo:
package com.study.maven.plugins;
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
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.net.URLEncoder;
import java.util.*;
/**
* Goal which touches a timestamp file.
*
* @goal touch
* @phase process-sources
*/
@Mojo(name = "count", defaultPhase = LifecyclePhase.COMPILE)
public class MyMojo extends AbstractMojo {
private static final Set<String> DEFAULT_FILE_TYPE = new HashSet<String>(Arrays.asList("java", "xml", "properties"));
private static final String EMPTY_STRING = "";
private static final String DOT = ".";
private static final String SEPARATOR = "------------------------------------------------------------------------";
private static final String UTF8 = "utf-8";
private static final int DEFAULT_MIN_SPACE_NUM = 5;
@Parameter(defaultValue = "${project.build.countRelBaseDir}", readonly = true)
private String countRelBaseDir;
private String countBaseDir;
private String countBaseDirEncoder;
@Parameter(defaultValue = "${project.build.fileType}", readonly = true)
private String fileType;
@Parameter(defaultValue = "${project.build.minSpaceNum}", readonly = true)
private Integer minSpaceNum;
private Set<String> fileTypeSet;
private int maxFilePathLen = 0;
private Log log = getLog();
public void execute() throws MojoExecutionException {
boolean isSuccess = true;
long totalLineCount = 0;
try {
init();
List<File> files = new ArrayList<>();
getFiles(files);
List<FileLineInfo> fileLineInfos = getFileLineInfo(files);
totalLineCount = formatPrint(fileLineInfos);
} catch (Exception e) {
isSuccess = false;
e.printStackTrace();
}
endPointPrint(isSuccess, totalLineCount);
}
private void endPointPrint(boolean isSuccess, long totalLineCount) {
log.info(SEPARATOR);
if (isSuccess) {
log.info("COUNT SUCCESS -> TOTAL LINE COUNT: " + totalLineCount);
} else {
log.info("COUNT FAIL");
}
log.info(SEPARATOR);
}
private long formatPrint(List<FileLineInfo> fileLineInfos) {
long totalLineCount = 0;
for (FileLineInfo fileLineInfo : fileLineInfos) {
totalLineCount += fileLineInfo.getLineCount();
log.info(getFormetLine(fileLineInfo));
}
return totalLineCount;
}
private String getFormetLine(FileLineInfo fileLineInfo) {
int spaceNum = maxFilePathLen + minSpaceNum - fileLineInfo.getFilePath().length();
StringBuilder formatLine = new StringBuilder(fileLineInfo.getFilePath());
while (spaceNum > 0) {
spaceNum--;
formatLine.append(DOT);
}
formatLine.append(fileLineInfo.getLineCount());
return formatLine.toString();
}
private List<FileLineInfo> getFileLineInfo(List<File> files) throws IOException {
List<FileLineInfo> fileLineInfos = new ArrayList<>();
for (File file : files) {
String filePath = file.getCanonicalPath().replaceFirst(countBaseDirEncoder, EMPTY_STRING);
Integer lineCount = countLine(file);
fileLineInfos.add(new FileLineInfo(filePath, lineCount));
maxFilePathLen = Math.max(maxFilePathLen, filePath.length());
}
return fileLineInfos;
}
private Integer countLine(File file) {
int count = 0;
try (FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr)) {
String line;
while ((line = br.readLine()) != null) {
if (MyStringUtils.isNotBlank(line.trim())) {
count++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return count;
}
private void getFiles(List<File> files) throws IOException {
File baseDir = new File(countBaseDir);
doGetFiles(baseDir, files);
}
private void doGetFiles(File currentFile, List<File> files) throws IOException {
if (currentFile.isDirectory()) {
File[] subs = currentFile.listFiles();
for (File sub : subs) {
doGetFiles(sub, files);
}
} else {
if (fileTypeSet.contains(getFileType(currentFile))) {
files.add(currentFile);
}
}
}
private String getFileType(File file) throws IOException {
String path = file.getCanonicalPath();
if (MyStringUtils.isBlank(path)) {
return EMPTY_STRING;
}
int lastIndexOf = path.lastIndexOf(".");
if (lastIndexOf == -1) {
return EMPTY_STRING;
}
if (lastIndexOf < path.length() - 1) {
return path.substring(lastIndexOf + 1);
}
return EMPTY_STRING;
}
private void init() throws IOException {
countBaseDir = getProjectDir();
if (MyStringUtils.isNotBlank(countRelBaseDir)) {
File file = new File(countBaseDir.concat(File.separator).concat(countRelBaseDir));
countBaseDir = file.getCanonicalPath();
}
countBaseDirEncoder = URLEncoder.encode(countBaseDir, UTF8);
log.info("-----countBaseDir:" + countBaseDir);
if (MyStringUtils.isBlank(fileType)) {
fileTypeSet = DEFAULT_FILE_TYPE;
} else {
fileTypeSet = new HashSet<>(Arrays.asList(fileType.trim().split(",")));
}
log.info("-----fileTypeSet:" + fileTypeSet);
if (minSpaceNum == null || minSpaceNum < 0) {
minSpaceNum = DEFAULT_MIN_SPACE_NUM;
}
log.info("-----minSpaceNum:" + minSpaceNum);
}
private String getProjectDir() {
return System.getProperty("user.dir");
}
}
效果:
參考:
1.https://www.runoob.com/maven/maven-build-life-cycle.html
2.https://blog.csdn.net/zjf280441589/article/details/53044308