生命太短暫,不要去做一些根本沒有人想要的東西。本文已被 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方法都啟不動了,那還得了。遇到這種情況,我只能使用百度大法(谷歌大法)了:
一看能搜出這么多結果,我也就不慌了,按照“教程”很容易的把問題解決了。另外呢,通過此次搜索到的結果聊兩句題外話:
- 雖然Result Count不少,但是我發現實質上內容幾乎一毛一樣,真乃天下文章一大抄
- 訪問量並不代表文章質量高,只是它剛好命中了關鍵字而已,比如標題黨
我得出如此感悟,也是促使我寫本文的原因之一。因為A哥的文章一貫如此,是有些B格的。接下來以點帶面,把這部分內容幫大家展開展開,解決問題並非最終目的,而是為了:記得牢,能裝x,一切為了加薪。
原因分析
出現此問題的直接原因是:IDEA集成開發環境運行你的“源碼”的時候(注意是源碼基礎上運行,並非打好的jar包哦),是通過命令(首行那個非常非常長的)來啟動Java進程的。這個命令主要包含兩大部分:
vm/程序
參數。也就是你看到的那些-XX -D等參數,這部分理論上可以無限長但實際上一般不會太長-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一共提供了三種命令行縮短器供你選擇:
- none。這是默認選項。IDE不會縮短長類路徑。如果命令行超出操作系統限制,則IDEA將無法運行您的應用程序
- jar manifest。IDE通過臨時classpath.jar傳遞長類路徑。原始類路徑在
MANIFEST.MF
中定義為classpath.jar中的類路徑屬性 - 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。推薦的解決方案有如下兩種:
- 將所有jar復制到一個公共文件夾,例如
c:\jars
,然后將其包括在內。這樣,每個jar都有一個短路徑,即c:\jars
(而不是長路徑c:\program files\app\lib\app-jar1.jar
),並且應該可以將這個路徑們控制在38kb之內 - 如果步驟1不起作用,則可以將單個jar提取到一個文件夾中,並創建一個包含所有提取文件的新jar。這樣就只需要引入這個新jar就可以了
這是兩種解決問題的思想:短路徑方式(簡單高效)和打包方式(100%能解決問題)
別問A哥為毛只給出windows的最大長度,沒有Mac的嗎?我只能說,我很窮所以用的是windows本,Mac的我不關心😄
思考題
今日份思考題比較簡單
- 為毛你的Spring Boot應用在生產環境下從來不用擔心出現Command line is too long這種錯誤?
- 有哪些有效的方式可以避免你的開發環境出現此問題?
總結
IDEA踩坑系列第一篇到這就結束了,算不算精彩呢?我個人覺得還可以😄。此專欄后續將不定期的更新,除了我自己准備外,同時也非常歡迎各位小伙伴能把平時遇到的IDEA遇到的棘手問題反饋給我(最好有解決方案哦),咱們一起把這個事做好,也算造福於大家嘛,畢竟我一個人碰見的case實則有限,有建議的可以下方掃碼加我好友私聊我。