Maven和Maven插件文章分類:
Java編程人生是一張茶幾,上面擺滿了杯具,請(qǐng)讓我們的杯具與眾不同。
這是我這篇博文的一個(gè)主題。
我們知道m(xù)aven是一個(gè)項(xiàng)目管理的工具,他把項(xiàng)目抽象為一個(gè)個(gè)的生命周期和階段。我們先來(lái)介紹一下maven最重要的幾個(gè)概念:
1、lifecycle 生命周期,一個(gè)項(xiàng)目在maven中有三個(gè)生命周期,分別為default,clean,site。default主要是編譯和部署生命周期,clean是清理生命周期,site是生成報(bào)表、工程文檔等生命周期。
2、phase 生命周期中階段。如default的生命周期中擁有validate、initialize、compile、test-compile、prepare-package、package、install、deploy等等的階段。階段是順序執(zhí)行的。
3、goal 階段中的目標(biāo)。每一個(gè)階段中,蘊(yùn)含著一個(gè)或多個(gè)目標(biāo)。
4、mojo 執(zhí)行目標(biāo)的具體代類
形象的來(lái)一個(gè)比喻,如同下面一張圖所示:
一個(gè)項(xiàng)目的生命周期如同一個(gè)人的生命周期(lifecycle),分為多個(gè)階段(phase),如3歲前是幼兒期,4-22歲是幼年期,23-53是中輕年期,51-70是老年期。而每個(gè)階段(phase)我們又會(huì)有不一樣的目標(biāo)(goal),比如幼兒期,我們的目標(biāo)(goal)是喝奶,幼年期的目標(biāo)(goal)是讀書(shū)、長(zhǎng)大,中年期的目標(biāo)是結(jié)婚生子等等等等。這些組成我們?nèi)松谋?。但是我們作為一個(gè)杯具的執(zhí)行者(mojo),還得一步一步的去走我們的各個(gè)階段,實(shí)現(xiàn)我們的各個(gè)目標(biāo)。
項(xiàng)目都有標(biāo)準(zhǔn)的生命周期,編譯前檢查、資源生成、編譯、部署、發(fā)布等等。但是每個(gè)項(xiàng)目又是如此不同,我們?cè)鯓痈淖兾覀兊捻?xiàng)目,使得這一個(gè)個(gè)的杯具有所不同呢?我們可以使用maven的插件和編寫maven的插件來(lái)實(shí)現(xiàn)。比如我們想在編譯前,去讀取一臺(tái)網(wǎng)絡(luò)設(shè)備的配置;再或則需要收集其他資源等等。maven插件讓我們項(xiàng)目豐富多彩,跟我們?nèi)松谋咭粯?,?qǐng)讓我們的杯具與眾不同。
講解了maven的一些概念以后,我們進(jìn)入maven插件的編寫講述上。
maven插件,也是以mojo來(lái)體現(xiàn)的,寫插件就是寫mojo。那為什么maven的標(biāo)準(zhǔn)mojo成為標(biāo)準(zhǔn)的生命周期中的goal實(shí)現(xiàn),而我們的插件就跟二奶一樣,不被承認(rèn),只能叫做插件呢。
比如我們?cè)谶\(yùn)行:maven install的時(shí)候,到底運(yùn)行了什么?我們讓maven執(zhí)行默認(rèn)生命周期中的一個(gè)階段(phase),這個(gè)階段叫install,而這個(gè)階段默認(rèn)綁定了一個(gè)目標(biāo)(goal),目標(biāo)的名稱也叫install。也就是說(shuō)我們讓maven喚醒項(xiàng)目的一次install目標(biāo)。如執(zhí)行maven install:install。maven會(huì)根據(jù)默認(rèn)的生命周期階段,先執(zhí)行先前的階段(validate,initialize...),然后執(zhí)行編譯和安裝。插件的運(yùn)行方式類似,如maven eclipse:eclipse 我們讓maven喚起運(yùn)行eclipse的插件,生成eclipse的項(xiàng)目文件。他們運(yùn)行方式如此的相似,是因?yàn)樗麄儽緛?lái)就是同樣的東西--mojo。
插件跟標(biāo)準(zhǔn)流程如同二奶跟合法妻子一樣。
1、他們都是不被承認(rèn)的
2、他們的存在都是為了解決需求
3、他們都是女人
1、插件也是不被maven承認(rèn)的
2、它們都是為了解決項(xiàng)目的需求
3、它們都是mojo
了解了我們的maven部分概念和插件的定位之后,我們來(lái)寫我們的第一個(gè)maven插件。插件之hello world。
所有的mojo都應(yīng)該繼承自org.apache.maven.plugin.AbstractMojo,我們來(lái)建立我們的maven插件工程。
Java代碼
mvn archetype:create -DgroupId=com.alibaba.maven.plugins -DartifactId=greeting-maven-plugin -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-mojo
跟普通Maven的項(xiàng)目一樣,自己定義groupId和artifactId。我們這里分別定義groupId為com.alibaba.maven.plugins和greeting-maven-plugin。
archetypeGroupId和archetypeArtifactId用來(lái)定位用哪個(gè)maven的工程模板來(lái)建立項(xiàng)目。當(dāng)然我們使用的是maven-archetype-mojo模板來(lái)建立插件項(xiàng)目。
Java代碼
/** @author xingming.zhaoxm
* @goal sayHello
*/
public class HelloWorldMojo extends AbstractMojo{
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info("Hello World!");
}}
Ok,如上所示我們復(fù)寫了execute方法,最重要@goal的一個(gè)annotation,它定義了這個(gè)mojo跟goal一一對(duì)應(yīng)的關(guān)系?,F(xiàn)在我們運(yùn)行命令mvn install 把該插件先發(fā)布到本地庫(kù)。之后我們便可以執(zhí)行我們的插件了。
插件的運(yùn)行方式為:mvn groupID:artifactID:version:goal
按照我們的項(xiàng)目,那么我們運(yùn)行插件應(yīng)該:mvn com.alibaba.maven.plugins:greeting-maven-plugin:1.0-SNAPSHOT:sayHello
看看,我們是不是已經(jīng)在控制臺(tái)看到我們打出的"Hello World"文字了。想想,為什么mvn eclipse:eclipse的插件運(yùn)行方式可以這么簡(jiǎn)單。
怎么減少輸入呢?
首先,我們?cè)趍aven的setting.xml配置文件中,可以找到這樣一個(gè)配置項(xiàng):
Java代碼
<pluginGroups>
<pluginGroup>*</pluginGroup>
</pluginGroups>
如果這里配置上我們的groupID,如我們的com.alibaba.maven.plugins,那么groupId的輸入便可省略了。
另外,我們的項(xiàng)目名稱DartifactId如果以${name}-maven-plugin或以maven-${name}-plugin的格式命名,我們便能省去-maven-plugin等信息。
version本來(lái)可以省略,maven會(huì)找到最新的版本來(lái)執(zhí)行。
那么省略后的執(zhí)行命令就可以這樣寫了:mvn greeting:sayHello
Ok,那么我要運(yùn)行插件時(shí)輸入?yún)?shù),該怎么處理呢?如同 mvn install -Dmaven.test.skip=true。我們重寫我們的mojo,加入@parameter的annotation。如下
Java代碼
/**
* @author xingming.zhaoxm
* @goal sayHello
*/
public class HelloWorldMojo extends AbstractMojo{
/**
* @parameter default-value="Somebody" expression="${username}
*/
private String userName;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info("Hello World!"+userName);
}}
在install一把,然后運(yùn)行
Java代碼
mvn greeting:sayHello -Dusername=白癡
看看是否已經(jīng)ok了。
上面的插件都在命令行模式下運(yùn)行,下面我再把項(xiàng)目中運(yùn)行的插件方式和方法做一個(gè)簡(jiǎn)要的梳理。這些類似的插件有很多,比如jetty插件,各種reporting插件等等。
我們先創(chuàng)建一個(gè)測(cè)試工程,用于應(yīng)用和測(cè)試我們寫的HelloWrold插件。
Java代碼
mvn archetype:create -DgroupId=com.alibaba -DartifactId=test
然后在pom文件中加入插件的依賴,如下
Xml代碼
<build>
<plugins>
<plugin>
<groupId>com.alibaba.maven.plugins</groupId>
<artifactId>greeting-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>sayHello</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
對(duì)該項(xiàng)目進(jìn)行編譯,mvn install 后,我們會(huì)發(fā)現(xiàn)在項(xiàng)目的initialize階段,便會(huì)打印出hello world!的信息。插件綁定到了特定的phase,如果我們不通過(guò)編譯該測(cè)試工程運(yùn)行插件,我們依然通過(guò)命令行,比如 mvn greeting:sayHello,我們會(huì)發(fā)現(xiàn),在綁定phase階段的先前階段會(huì)先順序執(zhí)行后,才開(kāi)始運(yùn)行插件。
插件配置中也可以配置參數(shù),優(yōu)先級(jí)以配置項(xiàng)為先,而命令行參數(shù)為后。如我們可以這樣配置插件參數(shù):
Xml代碼
<build>
<plugins>
<plugin>
<groupId>com.alibaba.maven.plugins</groupId>
<artifactId>greeting-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<configuration>
<userName>阿嬌</userName>
</configuration>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>sayHello</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
講完了插件以后,一些分享沒(méi)有涉及的知識(shí)點(diǎn)可以去參考maven的官方文檔。比如annotation中沒(méi)有涉及的一些點(diǎn)。可參考http://maven.apache.org/developers/mojo-api-specification.html
最后本想把一些插件的源碼拿出來(lái)解析一把,以后有時(shí)間再寫吧?;蛟S讀者們可以把這個(gè)事情當(dāng)做自己的提高手段。