最近在MINGW64控制台中使用 maven 命令打包時出現如下錯誤。通常在 eclipse 或 IDEA這樣的集成開發工具中,只要將工程的JDK環境變量重新設置一下,重新執行一下maven 打包命令即可。
1 [INFO] ------------------------------------------------------------------------ 2 [INFO] BUILD FAILURE 3 [INFO] ------------------------------------------------------------------------ 4 [INFO] Total time: 1.628 s 5 [INFO] Finished at: 2018-08-21T12:05:46+08:00 6 [INFO] ------------------------------------------------------------------------ 7 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project xxx-framework: Compilation failure 8 [ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK? 9 [ERROR] 10 [ERROR] -> [Help 1] 11 org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project xxx-framework: Compilation failure 12 No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK? 13 14 at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:213) 15 at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154) 16 at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146) 17 at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117) 18 at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81) 19 at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56) 20 at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128) 21 at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305) 22 at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192) 23 at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105) 24 at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956) 25 at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:290) 26 at org.apache.maven.cli.MavenCli.main (MavenCli.java:194) 27 at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) 28 at sun.reflect.NativeMethodAccessorImpl.invoke (Unknown Source) 29 at sun.reflect.DelegatingMethodAccessorImpl.invoke (Unknown Source) 30 at java.lang.reflect.Method.invoke (Unknown Source) 31 at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289) 32 at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229) 33 at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415) 34 at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356) 35 Caused by: org.apache.maven.plugin.compiler.CompilationFailureException: Compilation failure 36 No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK? 37 38 at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute (AbstractCompilerMojo.java:1161) 39 at org.apache.maven.plugin.compiler.CompilerMojo.execute (CompilerMojo.java:168) 40 at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137) 41 at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:208) 42 at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154) 43 at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146) 44 at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117) 45 at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81) 46 at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56) 47 at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128) 48 at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305) 49 at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192) 50 at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105) 51 at org.apache.maven.cli.MavenCli.execute (MavenCli.java:956) 52 at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:290) 53 at org.apache.maven.cli.MavenCli.main (MavenCli.java:194) 54 at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) 55 at sun.reflect.NativeMethodAccessorImpl.invoke (Unknown Source) 56 at sun.reflect.DelegatingMethodAccessorImpl.invoke (Unknown Source) 57 at java.lang.reflect.Method.invoke (Unknown Source) 58 at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289) 59 at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229) 60 at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415) 61 at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356) 62 [ERROR] 63 [ERROR] 64 [ERROR] For more information about the errors and possible solutions, please read the following articles: 65 [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException 66 [ERROR] 67 [ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <goals> -rf :xxx-framework
錯誤源頭分析:
我試了一下,在IDEA中是可以正常執行maven打包命令。由於這種錯誤出現過很多次,但是卻不知道其背后的原因,這次又碰到了,於是決定從源頭上看看究竟是什么原因導致的。根據上面的異常提示信息,一路追蹤下來,發現異常是從這個類(如下所示,該類位於plexus-compiler-javac-2.8.2.jar 之中)的方法拋出來的。
org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess(String[], CompilerConfiguration, String[])
很容易看出來是compiler等於null,導致出錯。而compiler變量是由執行 getJavaCompiler 方法后賦值的。進入到這個方法(如下所示,該方法位於plexus-compiler-javac-2.8.2.jar 之中)里面去看看。
org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.getJavaCompiler(CompilerConfiguration)
1 protected static JavaCompiler getJavaCompiler( CompilerConfiguration compilerConfiguration ) 2 { 3 switch ( compilerConfiguration.getCompilerReuseStrategy() ) 4 { 5 case AlwaysNew: 6 return ToolProvider.getSystemJavaCompiler(); 7 case ReuseCreated: //打斷點跟蹤會執行此處 8 JavaCompiler javaCompiler; 9 synchronized ( JAVA_COMPILERS ) 10 { 11 if ( JAVA_COMPILERS.size() > 0 ) 12 { 13 javaCompiler = JAVA_COMPILERS.get( 0 ); 14 JAVA_COMPILERS.remove( javaCompiler ); 15 return javaCompiler; 16 } 17 } 18 javaCompiler = ToolProvider.getSystemJavaCompiler(); 19 return javaCompiler; 20 case ReuseSame: 21 default: 22 return COMPILER; 23 } 24 25 }
打斷點跟蹤了一下,會執行 ReuseCreated 分支。JAVA_COMPILERS 列表大小為空,執行 ToolProvider.getSystemJavaCompiler(),進入到這個方法中,發現這個方法查找某接口的實現類(如下所示),然后加載該實現類並實例化。
javax.tools.ToolProvider.getSystemJavaCompiler()
private static final String defaultJavaCompilerName= "com.sun.tools.javac.api.JavacTool";
跟蹤到這兒,看到com.sun這個包我一時半會兒還沒有反應過來,這個是JDK私有的包。既然了找不到實現類,那我就創建一個實現該接口的類,這樣的話就不會報錯了,然而當我把眼光停留到控制台那行紅色錯誤提示信息上面,心想是不是應該使用 mvn -v 命令看一下,是不是加載的JDK路徑不對導致的? 在 MINGW64 中執行 mvn -v 命令,控制台打印出來的信息如下所示:
1 $ mvn -v 2 Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-25T03:49:05+08:00) 3 Maven home: D:\prog\apache-maven-3.5.3 4 Java version: 1.8.0_161, vendor: Oracle Corporation 5 Java home: C:\Program Files\Java\jre 6 Default locale: zh_CN, platform encoding: GBK 7 OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"
看到控制台輸出的Java home路徑,跟我在環境中配置的JAVA_HOME路徑不一樣,奇怪了? 打開cmd, 在cmd命令行中執行 mvn -v 命令,控制台打印出來的信息如下所示:
1 C:\Users\hyt>mvn -v 2 Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-25T03:49:05+08:00) 3 Maven home: D:\prog\apache-maven-3.5.3\bin\.. 4 Java version: 1.8.0_161, vendor: Oracle Corporation 5 Java home: C:\Program Files\Java\jdk1.8.0_161\jre 6 Default locale: zh_CN, platform encoding: GBK 7 OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"
對比之后,發現兩者不一樣,打開maven源碼工程,看一下執行 mvn -v 命令的輸出版本信息的方法,看一下究竟是從什么地方讀取JDK的路徑信息的。
org.apache.maven.cli.MavenCli#version private void version( CliRequest cliRequest ) { if ( cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) ) { System.out.println( CLIReportingUtils.showVersion() ); } }
org.apache.maven.cli.CLIReportingUtils#showVersion public static String showVersion() { final String ls = System.getProperty( "line.separator" ); Properties properties = getBuildProperties(); StringBuilder version = new StringBuilder( 256 ); version.append( buffer().strong( createMavenVersionString( properties ) ) ).append( ls ); version.append( reduce( properties.getProperty( "distributionShortName" ) + " home: " + System.getProperty( "maven.home", "<unknown Maven " + "home>" ) ) ) .append( ls ); version.append( "Java version: " ).append( System.getProperty( "java.version", "<unknown Java version>" ) ).append( ", vendor: " ).append( System.getProperty( "java.vendor", "<unknown vendor>" ) ).append( ", runtime: " ).append( System.getProperty( "java.home", "<unknown runtime>" ) ).append( ls ); version.append( "Default locale: " ).append( Locale.getDefault() ).append( ", platform encoding: " ).append( System.getProperty( "file.encoding", "<unknown encoding>" ) ).append( ls ); version.append( "OS name: \"" ).append( Os.OS_NAME ).append( "\", version: \"" ).append( Os.OS_VERSION ).append( "\", arch: \"" ).append( Os.OS_ARCH ).append( "\", family: \"" ).append( Os.OS_FAMILY ).append( '\"' ); return version.toString(); }
看到這兒我明白了,是在執行mvn命令的時候傳入JDK路徑不正確,我手動傳入JDK路徑來試試看能不能解決這個問題。我找到mvn.cmd文件,在該文件中(如下所示位置,使用notepad++編輯打開)設置JAVA_HOME路徑,在 MINGW64 中執行 mvn install 依然提示錯誤信息,mvn -v 打印出的信息中 java home 路徑依然是錯誤的。mvn -DJAVA_HOME=C:/Program Files/Java/jdk1.8.0_161/ install 采用這樣的方式強制傳入JAVA_HOME參數,導致maven根本無法識別 install 命令。
看來得研究一下 MINGW64 和 cmd 這兩者為什么打印出來的JDK路徑不一樣,難不成 MINGW64 沒有讀取系統環境變量。 不過在此之前我要先嘗試一下在 maven-compile-plugin 插件中增加<forceJavacCompilerUse>true</forceJavacCompilerUse> 配置項。因為前面代碼提示 compiler 為空,是因為使用了JavaxToolsCompiler來編譯源代碼,我讓maven直接使用javac命令來編譯源代碼,這樣就不會提示找不到complier,從而compiler為null,這樣做因該不會出錯。
org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile(CompilerConfiguration)
//省略方法 if ( isJava16() && !config.isForceJavacCompilerUse() ) { // use fqcn to prevent loading of the class on 1.5 environment ! result =org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess( args, config, sourceFiles ); } else { result = compileInProcess( args, config ); }
在工程的 pom.xml 文件中為 maven-compile-plugin 插件中增加 <forceJavacCompilerUse>true</forceJavacCompilerUse> 配置項。
1 <plugin> 2 <groupId>org.apache.maven.plugins</groupId> 3 <artifactId>maven-compiler-plugin</artifactId> 4 <!-- since 2.0 --> 5 <version>3.7.0</version> 6 <configuration> 7 <!-- use the Java 8 language features --> 8 <source>1.8</source> 9 <!-- want the compiled classes to be compatible with JVM 1.8 --> 10 <target>1.8</target> 11 <!-- The -encoding argument for the Java compiler. --> 12 <encoding>UTF8</encoding> 13 <forceJavacCompilerUse>true</forceJavacCompilerUse> 14 </configuration> 15 </plugin>
在 MINGW64 中執行 mvn install 命令,錯誤依舊
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project xxx-framework: Fatal error compiling: tools.jar not found: C:\Program Files\Java\jre\..\lib\tools.jar -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
沒辦法,回到設置 MINGW64 讀取windows環境變量的路子上來,只有這樣才能讀取正確的JDK路徑。可是在網上找了好長時間,都是說如何設置 MINGW64 的C++ gcc環境變量之類,不是自己想要。猛然腦海中想到3個字“注冊表”。果然在“注冊表”中找到與JDK相關的配置項。
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
問題的解決辦法:
編輯注冊表中相關的配置項,來解決這個問題。配置如下所示:
使用上面的配置之后,在 MINGW64 中執行 mvn install 命令之后,控制台提示報錯。
$ mvn install
Error: could not open `C:\Program Files\Java\jdk1.8.0_161\lib\amd64\jvm.cfg'
我在這個目錄下面去看了一下,果然沒有這個文件。在這個路徑 C:\Program Files\Java\jdk1.8.0_161\jre\lib\amd64 才有相關的配置,修改一下配置,如下所示:
在 MINGW64 中執行mvn install命令,控制台提示打包成功,mvn -v 輸出的信息顯示jdk路徑也配置正確。
原因分析:
對 C:\Program Files\Java\jre 和 C:\Program Files\Java\jdk1.8.0_161\jre 這二者之間的區別沒有弄清楚。開發的時候要指向JDK中的jre,因為要根據該jre的位置來做定位,加載JDK中的相關資源。比如上面maven要加載JDK中的com.sun私有包。關於這二者的區別可以在網上搜索,有關這方面的文章挺多的。
附CSDN上的某篇文章: java中的兩個jre區別 https://blog.csdn.net/sanjiaozhen/article/details/45157565