maven 在執(zhí)行package,install,deploy時(shí)使用clean與不使用clean的不同之處
有時(shí)候用mvn install
后,新改的內(nèi)容不生效,一定要后來(lái)使用mvn clean install 才生效,由于之前沒(méi)有做記錄,以及記不清是什么情況下才會(huì)出現(xiàn)的問(wèn)題,于是想看看clean和不clean的區(qū)別。
就如大家知道的,maven在執(zhí)行一個(gè)生命周期的命令的是時(shí)候?qū)?huì)執(zhí)行之前的所有生命周期操作,比如執(zhí)行mvn install,會(huì)執(zhí)行前面一系列的動(dòng)作包括 compile ,package , test 等,具體請(qǐng)查看maven的官方文檔。這個(gè)特性使maven的命令更加簡(jiǎn)潔易用。
再來(lái)分析原來(lái)的問(wèn)題,為什么修改的內(nèi)容不生效,肯定是最終打出來(lái)的war包中的內(nèi)容沒(méi)有更新,而war包中會(huì)依賴(lài)其他子工程的jar包,如果jar 包沒(méi)有更新過(guò),那war包調(diào)用老的jar包也會(huì)導(dǎo)致新內(nèi)容不生效。定位到問(wèn)題的原因應(yīng)該是jar包沒(méi)有用最新的資源(java或者配置文件),那jar包 又是什么時(shí)候,誰(shuí)去打的呢。
上面我們提到我們執(zhí)行mvn install的時(shí)候會(huì)先執(zhí)行mvn package,maven就是通過(guò)這個(gè)生命周期來(lái)根據(jù)用戶(hù)配置,進(jìn)行打包(war、jar或者其他),這會(huì)在每個(gè)工程 pom.xml 文件中設(shè)置,類(lèi)似如下:
<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"> ... <packaging>war</packaging> ... </project>
這里指定package的時(shí)候打成一個(gè)war包,改成jar,就會(huì)被打成jar包。
我們看jar形式的情況,mvn package 會(huì)調(diào)用 maven-jar-plugin 這個(gè)插件進(jìn)行打包。
下面我們做一些實(shí)驗(yàn)來(lái)看這個(gè)插件打包的時(shí)候的情況
1. 修改target目錄下打好的jar包中class以及配置文件的內(nèi)容,在運(yùn)行命令mvn package
,結(jié)果target包中的內(nèi)容沒(méi)有被覆蓋。
2. 修改源代碼中的內(nèi)容,再運(yùn)行命令mvn package
,結(jié)果target包中的內(nèi)容被覆蓋了,產(chǎn)生了新的包。
3. 修改target目錄下打好的jar包中的內(nèi)容,運(yùn)行命令mvn package -Djar.forceCreation
,這個(gè)參數(shù)應(yīng)該是強(qiáng)制創(chuàng)建jar包,所以結(jié)果target中的jar包內(nèi)容被覆蓋了,產(chǎn)生了新的jar包。
根據(jù)上面的實(shí)驗(yàn)好像還是不能解釋什么時(shí)候應(yīng)該用clean將target下面的內(nèi)容刪除重新生成,jar包,不過(guò)至少是明白了一些規(guī)則。
下面我們還是去看看maven-jar-plugin
的源碼吧。
之前,我提一點(diǎn),maven的debugg信息非常完備,需要查看debug信息只要在命令后面添加 -X 參數(shù)即可,如:
mvn clean package -X
就能看到非常豐富的DEBUG信息。
回來(lái),我們發(fā)現(xiàn)org.codehaus.plexus.archiver.AbstractArchiver
中的關(guān)鍵一段,用來(lái)判斷是否強(qiáng)制新建jar
protected boolean checkForced() throws ArchiverException { if ( !isForced() && isSupportingForced() && isUptodate() ) { getLogger().debug( "Archive " + getDestFile() + " is uptodate." ); return false; } return true; }
這個(gè)方法是校驗(yàn)是否強(qiáng)制重新創(chuàng)建jar包,只有當(dāng)
1. 沒(méi)有將 jar.forceCreation 參數(shù)設(shè)為true
2. 并且支持強(qiáng)制設(shè)置
3. up to date,意思就是被認(rèn)為是最新的內(nèi)容,沒(méi)有改動(dòng)
這個(gè)時(shí)候maven不進(jìn)行新包的生成直接返回。
protected void execute() throws ArchiverException, IOException { if ( ! checkForced() ) { return; } if ( doubleFilePass ) { skipWriting = true; createArchiveMain(); skipWriting = false; createArchiveMain(); } else { createArchiveMain(); } finalizeZipOutputStream( zOut ); }
所以除了那個(gè)強(qiáng)制的參數(shù)以外,就是看什么時(shí)候 isUptodate 為true,查看關(guān)鍵代碼:
protected boolean isUptodate() throws ArchiverException { final File zipFile = getDestFile(); final long destTimestamp = zipFile.lastModified(); if ( destTimestamp == 0 ) { getLogger().debug( "isUp2date: false (Destination " + zipFile.getPath() + " not found.)" ); return false; // File doesn't yet exist } final Iterator it = resources.iterator(); if ( !it.hasNext() ) { getLogger().debug( "isUp2date: false (No input files.)" ); return false; // No timestamp to compare } while ( it.hasNext() ) { final Object o = it.next(); final long l; if ( o instanceof ArchiveEntry ) { l = ( (ArchiveEntry) o ).getResource() .getLastModified(); } else if ( o instanceof PlexusIoResourceCollection ) { try { l = ( (PlexusIoResourceCollection) o ).getLastModified(); } catch ( final IOException e ) { throw new ArchiverException( e.getMessage(), e ); } } else { throw new IllegalStateException( "Invalid object type: " + o.getClass() .getName() ); } if ( l == PlexusIoResource.UNKNOWN_MODIFICATION_DATE ) { // Don't know what to do. Safe thing is to assume not up2date. getLogger().debug( "isUp2date: false (Resource with unknown modification date found.)" ); return false; } if ( l > destTimestamp ) { getLogger().debug( "isUp2date: false (Resource with newer modification date found.)" ); return false; } } getLogger().debug( "isUp2date: true" ); return true; }
代碼中提到有這么幾個(gè)情況,會(huì)認(rèn)為jar包不是最新的:
1. jar包不存在(其實(shí)就是mvn clean的效果)
2. 傳入比較的文件資源不存在
3. Resource with unknown modification date found,資源的修改時(shí)間未知
4. Resource with newer modification date found,jar包的最后修改時(shí)間比資源的最后修改時(shí)間早
總結(jié)
1. 理論上來(lái)講不做mvn clean 得到的jar包應(yīng)該是最新的,除非其他方式修改jar包中的內(nèi)容而不修改源代碼。
2. 平時(shí)可以用mvn install,而不進(jìn)行chean節(jié)省時(shí)間(如果你覺(jué)得節(jié)省時(shí)間多的話(huà)),但最保險(xiǎn)還是用 mvn clean install 生成最新的jar包或其他包
3. 不想用mvn clean又想保證jar包最新,建議添加-Djar.forceCreation
參數(shù)
4. 由maven的生命周期可知,當(dāng)使用deploy時(shí)同樣會(huì)有clean與不用clean的區(qū)別, 因此為了保險(xiǎn)起見(jiàn),建議package,install,deploy前均先clean
jar-plugin源代碼地址:http://svn.apache.org/repos/asf/maven/plugins/tags/maven-jar-plugin-2.4
到此這篇關(guān)于maven 在執(zhí)行package,install,deploy時(shí)使用clean與不使用clean的區(qū)別的文章就介紹到這了,更多相關(guān)maven 執(zhí)行package,install,deploy內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java開(kāi)發(fā)分布式服務(wù)框架Dubbo原理機(jī)制詳解
這篇文章主要為大家介紹了java開(kāi)發(fā)分布式服務(wù)框架Dubbo的原理機(jī)制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11java批量導(dǎo)入導(dǎo)出文件的實(shí)例分享(兼容xls,xlsx)
這篇文章主要給大家介紹了利用java批量導(dǎo)入導(dǎo)出文件的相關(guān)資料,文中給出了詳細(xì)的實(shí)例代碼,并且兼容xls,xlsx,對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,下面跟著小編一起來(lái)看看詳細(xì)的介紹吧。2017-06-06Java中MessageDigest來(lái)實(shí)現(xiàn)數(shù)據(jù)加密的方法
這篇文章主要介紹了Java中MessageDigest來(lái)實(shí)現(xiàn)數(shù)據(jù)加密的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05JAVA浮點(diǎn)數(shù)計(jì)算精度損失底層原理與解決方案
本文主要介紹了JAVA浮點(diǎn)數(shù)計(jì)算精度損失底層原理與解決方案。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02手寫(xiě)redis@Cacheable注解?參數(shù)java對(duì)象作為key值詳解
這篇文章主要介紹了手寫(xiě)redis@Cacheable注解?參數(shù)java對(duì)象作為key值詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01Java split函數(shù)拆分后變成null問(wèn)題解決方案
這篇文章主要介紹了Java split函數(shù)拆分后變成null問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Java線(xiàn)程操作的常見(jiàn)方法【線(xiàn)程名稱(chēng)獲取、設(shè)置、線(xiàn)程啟動(dòng)判斷等】
這篇文章主要介紹了Java線(xiàn)程操作的常見(jiàn)方法,結(jié)合實(shí)例形式總結(jié)分析了java線(xiàn)程的創(chuàng)建、線(xiàn)程名稱(chēng)的獲取、設(shè)置以及線(xiàn)程啟動(dòng)的判斷等相關(guān)操作實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-10-10Java中的形式參數(shù)和實(shí)際參數(shù)案例詳解
這篇文章主要介紹了Java中的形式參數(shù)和實(shí)際參數(shù),形參和實(shí)參間的關(guān)系,兩者是在調(diào)用的時(shí)候進(jìn)行結(jié)合的,通常實(shí)參會(huì)將取值傳遞給形參,形參去之后進(jìn)行函數(shù)過(guò)程運(yùn)算,然后可能將某些值經(jīng)過(guò)參數(shù)或函數(shù)符號(hào)返回給調(diào)用者,需要的朋友可以參考下2023-10-10