IDEA命令列縮短器助你解決此問題:Command line is too long. Shorten command line...

YourBatman發表於2020-07-18

生命太短暫,不要去做一些根本沒有人想要的東西。本文已被 https://www.yourbatman.cn 收錄,裡面一併有Spring技術棧、MyBatis、JVM、中介軟體等小而美的專欄供以免費學習。關注公眾號【BAT的烏托邦】逐個擊破,深入掌握,拒絕淺嘗輒止。

前言

各位小夥伴大家好,我是A哥。最近遇到兩個問題,都是關於IDEA的(言外之意和程式碼無關),很是讓我“生氣”呀(關鍵是浪費時間)。在痛定思痛後,我決定寫此專欄,來專門分享/記錄使用IntelliJ IDEA過程中遇到的那些奇葩問題和解決方案,以幫助你縮短日常排錯時間,這麼一思考好像還功德無量呢?。

IntelliJ IDEA作為Java開發者中最為流行的開發工具(eclipse粉勿噴),熟練掌握它(包括排雷)對提升編碼效率能有顯著提升。但工具畢竟是工具,這麼長時間使用IDEA以來,每個人或多或少的都遇到過關於IDEA七七八八、奇奇怪怪的問題,這些與程式碼舞棍,但它很容易偷走你的時間,半天又更或者是一天之久。

說明:千萬不要忽視對IDEA的研究,因為把它玩熟練了它就相當於你的物理外掛

本專欄內容並非 IDEA教程,而是著眼於分享IDEA使用過程中,那些我遇到(或者大家遇到)的但又不是能夠很快速解決,總之就是比較棘手的問題的彙總,有一種錯題本的意思有木有。總之就是希望它能夠幫助到大家迅速定位or解決問題,避免不必要的時間浪費,畢竟我們們的主業還是敲程式碼嘛~


版本約定

本文內容若沒做特殊說明,均基於以下版本:

  • IntelliJ IDEA:2020.1.2旗艦版

正文

使用IDEA這麼久,雖然之前時不時地的跟IDEA問題“交過手”,但真正促使我決定寫此專欄的原因還是源自於前兩天使用IDEA啟動Spring Boot程式時的這個報錯:

Error running 'Application': Command line is too long. Shorten command line for Application or also for Spring Boot default configuration.


說實話這個錯誤我前所未見,看起來還蠻有意思,因此決定研究一番。這不,把研究結果分享給大家,資訊共享。

為了解釋好這個問題,我們得先來做些功課,知曉寫概念。


控制檯首行路徑

在IDEA裡,你每次啟動一個main函式時,控制檯第一行輸出的“日誌”稱作為:控制檯首行路徑。這裡,我執行一個最最最簡單的程式,看看它長啥樣,程式如下:

public class Application {

    public static void main(String[] args) {
        System.out.println("Hello world");
    }
}

執行程式,控制檯輸出如下截圖:

相信小夥伴每天都能看見它但大概率不會注意到它,我也不例外。你想不到的是,恰巧這行“日誌”就成為了本文今天的主角,會圍繞它來展闡述。

特別說明:如果你是用外接tomcat驅動應用啟動的話效果不是這樣子的。因為它使用的是tomcat的指令碼來啟動,所以首行日誌形如這樣:D:\developer\apache-tomcat-9.0.34\bin\catalina.bat run


首行路徑內容

知道了什麼叫首行路徑,那麼它的內容才是我們要關心的。如上截圖中,細心的你會發現最後是...省略號,因此內容絕不止你現在看到的那麼簡單。你可以滑鼠點選一下,展開全部內容,截圖如下:

一行實在太長了,無法橫向截圖全部展示出來,因此我把它複製出來放在文字編輯器中檢視:

這個截圖是一行哦(只是我在文字編輯器了自動折行了而已),仍舊不能看到全部內容,因為字數真的太多了,總字數統計如下:

僅僅一行,字數超過26000個。咋舌吧:第一行控制檯“日誌”竟然輸出了超過2.6w個字元。從內容結構上來看,這是一個command命令:呼叫java.exe程式啟動一個java程式的命令


為何啟動拋錯Command line is too long

99.99%的情況下,你可以在IDEA里正常啟動你的應用,即使首行路徑很長很長。但是直到當我啟動我的這個Spring Boot應用時,彈出紅色提示:

直接禁止了我的running執行。提示內容中文釋義為:執行“Application”時出錯:命令列太長。縮短應用程式或Spring Boot預設配置的命令列。我相信如果你也是第一次見到此case,表情和我一樣是這樣的:

main方法都啟不動了,那還得了。遇到這種情況,我只能使用百度大法(谷歌大法)了:

一看能搜出這麼多結果,我也就不慌了,按照“教程”很容易的把問題解決了。另外呢,通過此次搜尋到的結果聊兩句題外話:

  1. 雖然Result Count不少,但是我發現實質上內容幾乎一毛一樣,真乃天下文章一大抄
  2. 訪問量並不代表文章質量高,只是它剛好命中了關鍵字而已,比如標題黨

我得出如此感悟,也是促使我寫本文的原因之一。因為A哥的文章一貫如此,是有些B格的。接下來以點帶面,把這部分內容幫大家展開展開,解決問題並非最終目的,而是為了:記得牢,能裝x,一切為了加薪。


原因分析

出現此問題的直接原因是:IDEA整合開發環境執行你的“原始碼”的時候(注意是原始碼基礎上執行,並非打好的jar包哦),是通過命令(首行那個非常非常長的)來啟動Java程式的。這個命令主要包含兩大部分:

  1. vm/程式引數。也就是你看到的那些-XX -D等引數,這部分理論上可以無限長但實際上一般不會太長
  2. -classpath引數,它用於指定執行時jar包路徑(因為jar包理論上是可以在任何地方的),這部分可能性就多了

關鍵就在於-classpath引數,它可以非常長,你依賴的jar包越多此路徑就越長;你的base基路徑越長它就越長;倘若你還要做複雜的Junit單元測試,那加入的jar包就更多長度可能就越長嘍。總的來說:此part是很有可能超長從而導致Command line is too long現象的。

如果類路徑太長(可能性大),或者您有許多VM引數(可能性小),則無法啟動該程式。原因是大多數作業系統都有命令列長度限制。在這種情況下,IntelliJ IDEA將提供嘗試縮短類路徑的能力。


IDEA老版本方案

針對此問題,在之前版本(確切的說是2017.3之前的版本),需要通過XML檔案配置來解決:找到工程下的.idea/workspace.xml這個檔案,新增如下項:

<component name="PropertiesComponent">
	...
	<!-- 這句是你需要新增的項 -->
	<property name="dynamic.classpath" value="true" />
	...
</component>

再次啟動程式發現問題解決。我有理由相信,在這個時間節點上應該沒有人用這麼古老的版本了吧,但你在網上搜的文章大多數都還是這種解決方案,因此請務必注意甄別哦(2017.3以後的版本請參照下面方案解決)。

所以我不是說了麼,任何不指定版本的解決方案、原始碼分析文章都是不太負責任的。作為一個程式設計師,應該適當提高自己的版本意識


IDEA新版本方案:命令列縮短器

在IDEA的2017.3版本中提供了一項新特性:命令列縮短器。旨在用來解決此類問題,也就是說從此版本開始,不再需要通過XML檔案來編輯IDE的設定那麼麻煩了,而是直接在介面操作即可:

最初,IntelliJ IDEA嘗試將長類路徑寫入文字檔案(這意味著應用程式是中間類載入器)。但是不幸的是,這不適用於某些框架,例如JMock。然後,IntelliJ IDEA嘗試使用或多或少的標準方法,即將長類路徑打包到classpath.jar中。不幸的是,對於其他一些框架,這也不起作用。

總結:這兩種方案都不是100%完美的,具體情況具體分析

從上對話方塊中可以看到IDEA一共提供了三種命令列縮短器供你選擇:

  1. none。這是預設選項。IDE不會縮短長類路徑。如果命令列超出作業系統限制,則IDEA將無法執行您的應用程式
  2. jar manifest。IDE通過臨時classpath.jar傳遞長類路徑。原始類路徑在MANIFEST.MF中定義為classpath.jar中的類路徑屬性
  3. classpath file。IDE將把長類路徑寫入文字檔案

jar manifest方式

選擇此種方式,執行測試程式,首行全部內容展示如下:

D:\developer\jdks\1.8.0_241\bin\java.exe -XX:TieredStopAtLevel=1 -noverify 
	-Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote 
	-Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain 
	-Dspring.application.admin.enabled=true 
	"-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\lib\idea_rt.jar=5975:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\bin" -Dfile.encoding=UTF-8 
	-classpath C:\Users\xxx\AppData\Local\Temp\classpath1199511058.jar 
	com.xxx.Application

區別主要在於-classpath這一行,它不再是把所有jar的路徑展示出來,而是“封裝”到了一個jar檔案裡,這一下子讓命令長度大幅減少,能夠100%保證不會超長了,所以啟動也就不會報錯嘍。

另外,在IDEA裡你直接單擊此jar路徑是可以預覽器內容的(真貼心):

當然,你也可以在你磁碟裡找到此jar檔案,然後檢視其內容(說明:請確保hold住執行緒了再去找對應檔案,否則臨時檔案是執行緒結束後就刪除了的):

特別強調:我在實踐過程中,使用此種方式出現過jar包沒有被載入進來的情況,在此提醒各位,若你也有類似現象發生,請切換成使用classpath file方式吧。

畢竟官方也說了:這兩種路徑縮短方式,對某些框架可能存在不相容情況,just可能而已哦~


classpath file方式

選擇此種方式,執行測試程式,首行全部內容展示如下:

D:\developer\jdks\1.8.0_241\bin\java.exe -XX:TieredStopAtLevel=1 -noverify 
	-Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote 
	-Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain 
	-Dspring.application.admin.enabled=true 
	"-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\lib\idea_rt.jar=5975:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\bin" -Dfile.encoding=UTF-8 
	-classpath C:\Users\xxx\AppData\Local\Temp\idea_classpath921151059
	com.xxx.Application

有了上面的描述,這個就不用A哥贅述了。



擴充套件知識:windows系統命令最大長度

這屬於擴充套件知識,延伸閱讀內容。

既然已經知道出現此問題的原因是命令超長了而“報錯”,A哥就想那windows命令最長允許多少字元呢?帶著這個問題,我開始了一番苦心尋找,最後終於在windows官網找到了我想要的答案。地址在這:https://docs.microsoft.com/zh-cn/windows/win32/api/processenv/nf-processenv-setenvironmentvariablea?redirectedfrom=MSDN

在Windows上,命令列長度最大為32767個字元(和shell長度、命令提示符長度的區別)。當提供足夠大的類路徑時,將違反此限制,並且Windows拒絕執行該命令並丟擲錯誤程式碼87。推薦的解決方案有如下兩種:

  1. 將所有jar複製到一個公共資料夾,例如c:\jars,然後將其包括在內。這樣,每個jar都有一個短路徑,即c:\jars(而不是長路徑c:\program files\app\lib\app-jar1.jar),並且應該可以將這個路徑們控制在38kb之內
  2. 如果步驟1不起作用,則可以將單個jar提取到一個資料夾中,並建立一個包含所有提取檔案的新jar。這樣就只需要引入這個新jar就可以了

這是兩種解決問題的思想:短路徑方式(簡單高效)和打包方式(100%能解決問題)

別問A哥為毛只給出windows的最大長度,沒有Mac的嗎?我只能說,我很窮所以用的是windows本,Mac的我不關心?


思考題

今日份思考題比較簡單

  1. 為毛你的Spring Boot應用在生產環境下從來不用擔心出現Command line is too long這種錯誤?
  2. 有哪些有效的方式可以避免你的開發環境出現此問題?

總結

IDEA踩坑系列第一篇到這就結束了,算不算精彩呢?我個人覺得還可以?。此專欄後續將不定期的更新,除了我自己準備外,同時也非常歡迎各位小夥伴能把平時遇到的IDEA遇到的棘手問題反饋給我(最好有解決方案哦),我們們一起把這個事做好,也算造福於大家嘛,畢竟我一個人碰見的case實則有限,有建議的可以下方掃碼加我好友私聊我。

相關文章