天天看點

java.lang.InstantiationError: sun.net.ftp.FtpClient

今天排查老系統上傳檔案報錯問題時發現線上環境控制台報錯java.lang.InstantiationError: sun.net.ftp.FtpClient

随手複制粘貼百度,很容易找到了原因,在jdk1.6中FtpClient是有空的構造函數的,但是到了jdk1.7之後FtpClient的空構造函數就被私有化了

帶着這個答案我閱讀了項目的代碼,發現在報錯資訊所指代碼行處有一個ftpClient = new FtpClient();,這樣更進一步的驗證了答案

首先将對應的錯誤class檔案從線上伺服器下載下傳下來,然後使用EditPlus打開,打開後會有一個彈框讓我們選擇以什麼字元編碼打開class檔案,這裡我們選擇Hex viewer(16進制字元編碼)

java.lang.InstantiationError: sun.net.ftp.FtpClient

然後檢視第一行的前8個組合:CA FE BA BE 00 00 00 32,這裡我們的class檔案是被jdk1.6編譯的

1:前面8個位元組CA FE BA BE是固定的。

2:随後4個位元組00 00是次版本号

3:再後面的4個位元組00 34是JDK的版本号。

 JDK版本号對應關系如下:

      34(對應十進制的50):JDK1.8

      33(對應十進制的50):JDK1.7

      32(對應十進制的50):JDK1.6

      31(對應十進制的49):JDK1.5

  30(對應十進制的48):JDK1.4

  2F(對應十進制的47):JDK1.3

  2E(對應十進制的46):JDK1.2

java.lang.InstantiationError: sun.net.ftp.FtpClient

到線上伺服器tomcat的bin下執行./version.sh,發現用的是jdk1.7,也就是我jdk1.6編譯的class檔案現在運作在jdk1.7環境下,然後FtpClient的空構造函數在jdk1.7下是私有的,是以運作的時候代碼會報錯

java.lang.InstantiationError: sun.net.ftp.FtpClient

rpm -qa|grep java 檢視目前伺服器有哪些jdk,我們需要jdk1.6,發現伺服器上已經有了jdk1.6

java.lang.InstantiationError: sun.net.ftp.FtpClient

這時候我們需要找到jdk1.6的路徑,使用find -name rt.jar,這裡為什麼找rt.jar呢,因為我嘗試了很多關鍵詞,發現找不到,然後想到每個jdk中都自帶rt.jar,是以直接找這個檔案,可以迅速找到jdk的檔案路徑

找到路徑後進入tomcat的bin目錄下,vim操作catalina.sh檔案,在檔案的頭部添加一段代碼(這裡注意不要放到檔案第一行,要放到被注釋的指令的後面)

java.lang.InstantiationError: sun.net.ftp.FtpClient

export JAVA_HOME=/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre

這裡加這段代碼的含義是tomcat啟動時将JAVA_HOME替換成jdk1.6,這樣tomcat的jdk就變成了1.6,再到tomcat的bin下執行./version.sh,發現這時候tomcat的jdk版本是1.6

然後啟動服務,上傳檔案,問題解決!

繼續閱讀