1. 程式人生 > >Jib構建映象的問題分析(Could not find or load main class ${start-class})

Jib構建映象的問題分析(Could not find or load main class ${start-class})

問題簡述

通過Jib外掛將SpringBoot工程製作成Docker映象成功,但是執行映象的時候報錯(Could not find or load main class ${start-class}),今天來一起分析這個問題,希望能幫讀者跳過小坑。

關於Jib外掛

在Maven工程中可以使用Jib外掛將當前Java工程構建成Docker映象,詳情請參考:

  1. 《Docker與Jib(maven外掛版)實戰》;
  2. 《Jib使用小結(Maven外掛版)》;

環境資訊

  1. 作業系統:macOS Mojave 10.14.6 (18G103)
  2. JDK:10.14.6 (18G103)
  3. Docker:10.14.6 (18G103)
  4. SpringBoot:2.1.8.RELEASE
  5. Jib外掛版本:1.6.1

原始碼下載

為了重現問題,我將出現問題的SpringBoot工程上傳到GitHub,地址和連結資訊如下表所示:

名稱 連結 備註
專案主頁 https://github.com/zq2599/blog_demos 該專案在GitHub上的主頁
git倉庫地址(https) https://github.com/zq2599/blog_demos.git 該專案原始碼的倉庫地址,https協議
git倉庫地址(ssh) [email protected]:zq2599/blog_demos.git 該專案原始碼的倉庫地址,ssh協議

</br>

這個git專案中有多個資料夾,本章的應用在jib-error-demo資料夾下,如下圖紅框所示: 在這裡插入圖片描述

問題:

  1. 在pom.xml檔案所在目錄執行命令<font color="blue">mvn clean compile -U</font>,映象可以構建成功,但是控制檯輸出了警告資訊,如下圖: 在這裡插入圖片描述
  2. 嘗試用此映象建立容器,行命令<font color="blue">docker run --name=test bolingcavalry/hellojib:0.0.1-SNAPSHOT</font>,報錯如下:
CN0014005932:~ zhaoqin$ docker run --name=test bolingcavalry/hellojib:0.0.1-SNAPSHOT
Error: Could not find or load main class ${start-class}
  1. <font color="blue">docker ps -a</font>檢視容器資訊如下,只能看到狀態是"退出",別的沒啥了:
CN0014005932:~ zhaoqin$ docker ps -a
CONTAINER ID        IMAGE                                   COMMAND                  CREATED             STATUS                     PORTS               NAMES
d618f6588821        bolingcavalry/hellojib:0.0.1-SNAPSHOT   "java -Xms4g -Xmx4g …"   4 minutes ago       Exited (1) 4 minutes ago                       test
  1. 不甘心,用命令<font color="blue">docker ps -a --no-trunc</font>檢視未截斷的容器資訊:
CN0014005932:~ zhaoqin$ docker ps -a --no-trunc
CONTAINER ID                                                       IMAGE                                   COMMAND                                                                           CREATED             STATUS                     PORTS               NAMES
d618f6588821f00d3bd0b67a85ff92988b90dfff710370c9d340d5c544c550af   bolingcavalry/hellojib:0.0.1-SNAPSHOT   "java -Xms4g -Xmx4g -cp /app/resources:/app/classes:/app/libs/* ${start-class}"   7 minutes ago       Exited (1) 7 minutes ago                       test
  1. 這次有新發現,容器啟動時執行命令是<font color="blue">java -Xms4g -Xmx4g -cp /app/resources:/app/classes:/app/libs/* ${start-class}</font>,怪哉!這個<font color="red">${start-class}</font>是什麼?我們來看一個正常映象的啟動命令:
java -Xms4g -Xmx4g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.jiberrordemo.JibErrorDemoApplication

如上所示,<font color="blue">com.bolingcavalry.jiberrordemo.JibErrorDemoApplication</font>是main方法所在類,此命令可以正常執行JibErrorDemoApplication類的main方法; 6. 小結問題:容器啟動時執行java命令,把<font color="blue">${start-class}</font>作為引數傳給java,導致java無法處理此引數,所以程序報錯,導致容器退出;

問題原因

此問題的原因很簡單:<font color="blue">java工程中帶有main方法的類不止一個</font>,去檢視jib-error-demo工程的程式碼,發現Utils.java中果然有個main方法:

public class Utils {

    public static String time(){
      return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()).toString();
    }

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

將上述main方法刪除掉,再構建映象並執行容器,證實問題已經解決。

另一種解決問題的方法

如果不想動Utils類的程式碼(也許jar包中某個類帶有main方法),請開啟pom.xml檔案,在jib外掛的配置中增加<font color="blue">mainClass</font>節點,節點內容是指定的class類,如下圖紅框所示: 在這裡插入圖片描述 經過上面的設定,問題也可以解決。

接下來,如果您有興趣瞭解更深層次的原因,咱們一起來深度探險吧。

查詢問題

  1. 這個問題在Jib的官方GitHub上是有記錄的,先看第一條,地址是:https://github.com/GoogleContainerTools/jib/issues/1601 ,如下圖紅框所示,同樣的問題,最後issue的發起人自己關閉了這個issue,因為他發現這自己的專案中有兩個帶有main方法的類: 在這裡插入圖片描述
  2. 再來看看這個issue, https://github.com/GoogleContainerTools/jib/issues/170 ,Jib的作者Q Chen推測是Spring將<font color="blue">${start-class}</font>這個字串設定為Main-Class屬性的值(個人感覺,這裡說的Spring應該是spring boot的mave外掛吧),於是Jib外掛在使用Main-Class的值得時候,拿到的就是<font color="blue">${start-class}</font>這個字串了: 在這裡插入圖片描述
  3. 170這個issue的後續情節很有意思,Jib作者Q Chen對這個問題也很糾結,如果Java工程中發現了多個帶有main方法的類,Jib究竟該如何處理呢?Q Chen最後決定輸出警告,如下圖: 在這裡插入圖片描述
  4. 一起來看看這段程式碼吧,也就是上圖中#288,地址是:https://github.com/GoogleContainerTools/jib/pull/228/files/c8757e1f9ea47edd78df18142de7836a68f22034 ,如果mainClass不像一個class類的名稱,就輸出警告,這個邏輯在Gradle和Maven外掛中都寫入了: 在這裡插入圖片描述
  5. 最後一個問題:上面程式碼中的mainClass從哪來的?開啟上圖的原始碼,地址是:https://github.com/GoogleContainerTools/jib/blob/c8757e1f9ea47edd78df18142de7836a68f22034/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildImageMojo.java ,如下圖紅框,從方法名可以推測,該值來自構建SpringBoot工程的maven外掛,所以前面Q Chen提到main-class變數的值是Spring修改的,應該是來自這段程式碼: 在這裡插入圖片描述 此時的您,如果依然意猶未盡,咱們再來鞏固一下SpringBoot的start-class

關於start-class

  1. 熟悉SpringBoot的同學其實對<font color="blue">${start-class}</font>並不陌生,當工程中多個類中都有<font color="blue">main</font>方法時,使用該引數來指定SpringBoot的啟動類;
  2. 先看SpringBoot官方文件熟悉一下<font color="blue">start-class</font>,地址是:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/ ,下圖內容比較關鍵:我們設定的啟動類被指定到<font color="blue">Start-Class</font>屬性中,而<font color="blue">Main-Class</font>屬性變成了<font color="blue">org.springframework.boot.loader.JarLauncher</font>,這才是SpringBoot真正的啟動類: 在這裡插入圖片描述
  3. 如下圖,這是個補充說明,<font color="blue">Main-Class</font>屬性的值被轉移到<font color="blue">Start-Class</font>屬性這個動作,是maven外掛在構建jar的時候做的: 在這裡插入圖片描述
  4. 所以start-class的值是來自main-class,再看main-class的值從哪裡來,如下圖紅框所示,maven外掛會去查詢帶有<font color="blue">public static void main(String[] args)</font>的類: 在這裡插入圖片描述 至此,Jib構建的映象問題分析完畢,一個小小的問題引發了這麼多學習和探索,雖然有點費時間,但是可以讓人再次感受到"技術是相通的"感覺,不知道您有沒有這種感覺呢?

歡迎關注我的公眾號:程式設計師欣宸

在這裡   
 
 </div> 
 <div class=

相關推薦

Jib構建映象的問題分析(Could not find or load main class ${start-class})

問題簡述 通過Jib外掛將SpringBoot工程製作成Docker映象成功,但是執行映象的時候報錯(Could not find

Linux終端運行java源碼出錯——Error: Could not find or load main class [duplicate]

終端 -o erro main spa class文件 img not find https Linux終端中運行.class文件出錯 Linux終端運行java源碼出錯——Error: Could not find or load main class [duplicat

hadoop 3.1.1 Could not find or load main class org.apache.hadoop.mapreduce.v2.app.MRAppMaster

name ado org 3.1.1 div 9.png per mapred 技術分享 啟動hdfs後執行share目錄中自帶的mapreduce程序時報如下錯誤 找到$HADOOP_HOME/etc/mapred-site.xml,增加以下配置 1 <p

在idea裡執行maven專案出現:Error: Could not find or load main class com.xxx.xxxx

原因分析:maven專案在執行時找不到主類,也就是專案啟動類找不到。可以嘗試以下方法。 思路:java檔案必須經過compile才會變成.class檔案,找不到.class檔案就是由於沒有經過編譯導致的。 可能是由於對maven專案執行了mvn clean命令,沒有執行mvn compile

flume啟動報錯 Could not find or load main class org.apache.flume.node.Application

修改flume的資料夾名稱後,啟動flume可能會失敗,錯誤資訊如下: Error: Could not find or load main class org.apache.flume.node.Application 這個是因為環境變數的問題。 export看一下是不是有個FLUME_HOME的

zookeeper SolrCloud 叢集配置 Error: Could not find or load main class org.apache.solr.cloud.ZkCLI

搭建SolrCloud叢集  把solrhome中的配置檔案上傳到zookeeper叢集。使用zookeeper的客戶端上傳。 客戶端命令位置:/root/solr-4.10.3/example/scripts/cloud-scripts 執行命令  ./zk

搭建SolrCloud叢集Could not find or load main class org.apache.solr.cloud.ZkCLI

搭建SolrCloud叢集 報錯解決方案 1、把solrhome中的配置檔案上傳到zookeeper叢集。 //1、進入cloud-scripts目錄下 (以下IP為示例,請根據自己實際配置填寫) cd /root/solr-4.10.3/example/scripts/cloud-

報錯:Error: Could not find or load main class org.apache.flume.tools.GetJavaProperty

輸入flume-ng version 啟動flume時報錯Error: Could not find or load main class org.apache.flume.tools.GetJavaProperty,但似乎已經啟動. 這時我們可以去hbase中修改hbase-e

java報錯-找不到或無法載入主類(Error: Could not find or load main class)

文章目錄 CLASSPATH配置問題 package問題 解決方法1:刪除package宣告 解決方法2:指定包名 比如說test.java package test; public

Sqoop找不到主類 Error: Could not find or load main class org.apache.sqoop.Sqoop

最近由於要使用Sqoop來到出資料到hdfs,可是發現Sqoop1.4.5跟hadoop2.X不相容,需要對Sqoop1.4.5進行編譯,編譯的具體方法見:http://my.codeweblog.com/AlbertHa/blog/318551 如果一切都順利的話需要就不會遇到什麼問題,但是有一個問題一直

Linux 下 Error: Could not find or load main class Hello

在linux下寫了一個非常簡單的Hello world程式,編譯執行竟然報錯:Error: Could not find or load main class Hello 最後發現是CLASSPATH的問題。 主要在環境變數這塊: export JAVA_HOME=/u

搭建SolrCloud: Error: Could not find or load main class org.apache.solr.cloud.ZkCLI

【./zkcli.sh:line 13: unzip: command not found    Error: Could not find or load main class org.apache

Travis CI Could not find or load main class org.gradle.wrapper.GradleWrapperMain 錯誤

問題 在 Travis CI 編譯的時候出現 Error: Could not find or load main

解決Qt編譯動態連結庫could not find or load the Qt platform plugin "windows" in.問題

最近用Qt5做了一個專案的介面,在編譯成可執行檔案EXE之後,執行檔案,提示: This application failed to start because it could not find or load the Qt platfo rm plugin "windows" in "".

This application failed to start because it could not find or load the Qt platform plugin windows

Qt 程式報錯 This application failed to start because it could not find or load the Qt platform plugin “windows” 如下圖 今天遇到一個很奇怪的問題,Qt應用程

板子執行qt程式could not find or load the Qt platform plugin "xcb"

交叉編譯qt5後放板子上執行應用程式,./qtest 出錯could not find or load the Qt platform plugin "xcb" ls /usr/local/qt5-arm/plugins/platforms/ libqlinuxfb.so

This application failed to start because it could not find or load the Qt platforms plugins

 由於一直在linux下操作,今天Qt移植平臺的時候導致.exe可執行檔案一直執行不起來,提示缺少某些dll庫,這個問題解決起來簡單(直接去qt原始碼裡面查詢對應庫新增到可執行檔案目錄就行),但是之後

could not find or load the Qt platform plugin windows的解決方法

VS+Qt5環境下建立一個Qt工程,在本機執行沒問題,可是把.exe和用到的.dll打包發到別人電腦上卻執行不了,報錯如下: 為什麼會這樣?這是因為程式執行需要Qt本身的一些dll,把這些缺失的dll補上就可以了。 需要注意的是:一般遇到這個報錯,是缺少plugins

【qt錯誤】This application failed to start because it could not find or load

qt釋出exe無法執行,提示plugin windows錯誤 This application failed to start because it could not find or load the Qt platform plugin “window

[pyqt5]解決could not find or load the Qt platform plugin windows

在PyQt5+python3+pycharm開發環境配置時,遇到了This application failed to start because it could not find or load