命令行太长导致无法启动

问题描述:

运行 EmergingArtistApplication 时出错。命令行太长。通过 JAR 清单或通过类路径文件缩短命令行并重新运行。

Error running EmergingArtistApplication. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun.

问题分析

控制台首行路径在IDEA里,你每次启动一个main函数时,控制台第一行输出的“日志”称作为:控制台首行路径。例如:

public class Application { 
    public static void main(String[] args) { 
        System.out.println("Hello world"); 
    } 
}
复制代码

运行程序,控制台输出如下截图:

006071446358.png 如果你是用外置tomcat驱动应用启动的话效果不是这样子的。因为它使用的是tomcat的脚本来启动, 所以首行日志形如这样:D:\developer\apache-tomcat-9.0.34\bin\catalina.bat run

如上截图中,细心的你会发现最后是...省略号,因此内容绝不止你现在看到的那么简单。你可以鼠标点击一下,展开

607145503910dd.png 全部内容,这一行实在太长了,无法横向截图全部展示出来,因此我把它复制出来放在文本编辑器中查看:

06071504144q5.png 这个截图是一行哦(只是我在文本编辑器了自动折行了而已),仍旧不能看到全部内容,因为字数真的太多了,总字数统计如下:截图如下:

6071505qw18466.png

第一行控制台“日志”竟然输出了超过2.6w个字符。从内容结构上来看,这是一个command命令:调用java.exe程序启动一个java进程的命令。

为何启动抛错Command line is too long?99.99%的情况下,你可以在IDEA里正常启动你的应用,即使首行路径很长很长。但是直到当我启动我的这个Spring Boot应用时,弹出红色提示:

60714144qq5942.png

原因分析

出现此问题的直接原因是: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文件来编辑IDE的设置那么麻烦了,而是直接在界面操作即可:

60715420478sdsd1.png

最初,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路径是可以预览器内容的:

607sd160409685.png

当然,你也可以在你磁盘里找到此jar文件,然后查看其内容(说明:请确保hold住线程了再去找对应文件,否则临时文件是线程结束后就删除了的):

6071605363sds76.png

特别强调:我在实践过程中,使用此种方式出现过jar包没有被加载进来的情况,在此提醒各位,若你也有类似现象发生,请切换成使用classpath file方式吧。

毕竟官方也说了:这两种路径缩短方式,对某些框架可能存在不兼容情况。

选择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

扩展知识:

在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%能解决问题)。

Guess you like

Origin juejin.im/post/7069605158325321736