編寫(xiě)maven插件的步驟
一:創(chuàng)建maven-plugin項(xiàng)目
創(chuàng)建一個(gè)普通的maven項(xiàng)目,只是packaging改為maven-plugin,同時(shí)引入依賴(lài)maven-plugin-api。pom文件如下:
<?xml version="1.0" encoding="UTF-8"?><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.sawyer.edu</groupId> <artifactId>maven-loc-plugin</artifactId> <version>1.0-SNAPSHOT</version> <packaging>maven-plugin</packaging> <properties> <maven.version>3.0</maven.version> </properties> <dependencies> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>${maven.version}</version> </dependency> </dependencies></project>
二:創(chuàng)建一個(gè)CountMojo類(lèi)。該類(lèi)所必要的三項(xiàng)工作:繼承AbstractMojo、實(shí)現(xiàn)execute()方法、提供@goal標(biāo)注。代碼如下:

package com.sawyer.edu.tlsys.plugin;import org.apache.maven.model.Resource;import org.apache.maven.plugin.AbstractMojo;import org.apache.maven.plugin.MojoExecutionException;import org.apache.maven.plugin.MojoFailureException;import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.io.IOException;import java.util.ArrayList;import java.util.List;/** * maven 代碼統(tǒng)計(jì)插件 * @author sawyer * @goal count */public class CountMojo extends AbstractMojo { /** * default includes */ private static final String[] INCLUDES_DEFAULT = {"java", "xml", "properties"}; /** * @parameter expression = "${project.basedir}" * @required * @readonly */ private File basedir; /** * @parameter expression = "${project.build.sourceDirectory}" * @required * @readonly */ private File sourceDirectory; /** * @parameter expression = "${project.build.testSourceDirectory}" * @required * @readonly */ private File testSourceDirectory; /** * @parameter expression = "${project.build.resources}" * @required * @readonly */ private List<Resource> resources; /** * @parameter expression = "${project.build.testResources}" * @required * @readonly */ private List<Resource> testResources; /** * file types which will be included for counting * @parameter */ private String[] includes; /** * execute * @throws MojoExecutionException MojoExecutionException * @throws MojoFailureException MojoFailureException */ public void execute() throws MojoExecutionException, MojoFailureException { if(includes == null || includes.length == 0){ includes = INCLUDES_DEFAULT; } try{ countDir(sourceDirectory); countDir(testSourceDirectory); for(Resource resource : resources){ countDir(new File(resource.getDirectory())); } for(Resource testResource : testResources){ countDir(new File(testResource.getDirectory())); } }catch (Exception e){ throw new MojoExecutionException("count failed:", e); } } /** * 統(tǒng)計(jì)某個(gè)目錄下文件的代碼行 * @param dir 目錄 * @throws IOException 文件異常 */ private void countDir (File dir) throws IOException{ if(!dir.exists()){ return; } List<File> collected = new ArrayList<File>(); collectFiles(collected, dir); int lines = 0; for(File sourceFile : collected){ lines += countLine(sourceFile); } String path = dir.getAbsolutePath().substring(basedir.getAbsolutePath().length()); getLog().info(path + ": " + lines + " lines of code in " + collected.size() + "files"); } /** * 遞歸獲取文件列表 * @param collected 文件列表list * @param file 文件 */ private void collectFiles(List<File> collected, File file){ if(file.isFile()){ for(String include : includes){ if(file.getName().endsWith("." + include)){ collected.add(file); break; } } }else{ for(File sub : file.listFiles()){ collectFiles(collected, sub); } } } /** * 讀取文件的行數(shù) * @param file 文件對(duì)象 * @return line * @throws IOException 文件操作異常 */ private int countLine(File file) throws IOException{ BufferedReader reader = new BufferedReader(new FileReader(file)); int line = 0; try{ while(reader.ready()){ reader.readLine(); line++; } }finally { reader.close(); } return line; }}CountMojo代碼
這里要關(guān)注的是@goal標(biāo)注,這個(gè)標(biāo)注就是這個(gè)類(lèi)的目標(biāo),定義了目標(biāo)之后,我們才可以在項(xiàng)目中配置該插件目標(biāo)。
代碼中還包含了basedir、sourceDirectory、testSourceDirectory等字段,它們都使用了@parameter標(biāo)注,同時(shí)關(guān)鍵字expression表示從系統(tǒng)屬性中讀取這幾個(gè)字段值。
其次,代碼中的includes字段就是用來(lái)為用戶(hù)提供該配置點(diǎn)的,它的類(lèi)型為String數(shù)組,并且使用了@parameter參數(shù)表示用戶(hù)可以自己在pom中配置該字段,使用該插件時(shí)的pom配置如下:
<plugin> <groupId>com.iflytek.edu</groupId> <artifactId>maven-loc-plugin</artifactId> <version>1.0-SNAPSHOT</version> <configuration> <includes> <include>java</include> <include>sql</include> </includes> </configuration> <executions> <execution> <phase>compile</phase> <goals> <goal>count</goal> </goals> </execution> </executions></plugin>
根據(jù)上面的pom配置,可以看到incuudes字段標(biāo)識(shí)需要統(tǒng)計(jì)的文件后綴,phase表示該插件在compile階段工作,使用該插件的時(shí)候可以看到如下輸出信息:
[INFO] --- maven-loc-plugin:1.0-SNAPSHOT:count (default) @ ZX-jobmonitor-webapp ---[INFO] /src/main/java: 778 lines of code in 6files[INFO] /src/test/java: 0 lines of code in 0files[INFO] /src/main/resources: 0 lines of code in 0files
使用mvn clean install命令將該插件項(xiàng)目構(gòu)建并安裝到本地倉(cāng)庫(kù)后,并按照上面的pom配置,就可以使用它統(tǒng)計(jì)項(xiàng)目的代碼了。
三:錯(cuò)誤處理和日志
上面的CountMojo類(lèi)繼承自AbstratctMojo,跟蹤會(huì)發(fā)現(xiàn)該抽象類(lèi)實(shí)現(xiàn)了類(lèi)Mojo接口,execute()方法就是在這個(gè)接口中定義的。
void execute() throws MojoExecutionException, MojoFailureException;
這個(gè)方法可以拋出兩種異常,
如果是MojoFailureException異常,則表示為發(fā)現(xiàn)了預(yù)期的錯(cuò)誤,例如單元測(cè)試插件在發(fā)現(xiàn)測(cè)試失敗時(shí)就會(huì)拋出該異常。
如果是MojoExcutionException異常,則表示發(fā)現(xiàn)了未預(yù)期的異常,例如上述代碼中的IOException等。
四:測(cè)試
可在項(xiàng)目中直接集成該插件,也可以在項(xiàng)目目錄下用命令行來(lái)測(cè)試該插件,命令如下:
mvn com.sawyer.edu:maven-loc-plugin:1.0-SNAPSHOT:count
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注