今天排查老系統上傳檔案報錯問題時發現線上環境控制台報錯java.lang.InstantiationError: sun.net.ftp.FtpClient
随手複制粘貼百度,很容易找到了原因,在jdk1.6中FtpClient是有空的構造函數的,但是到了jdk1.7之後FtpClient的空構造函數就被私有化了
帶着這個答案我閱讀了項目的代碼,發現在報錯資訊所指代碼行處有一個ftpClient = new FtpClient();,這樣更進一步的驗證了答案
首先将對應的錯誤class檔案從線上伺服器下載下傳下來,然後使用EditPlus打開,打開後會有一個彈框讓我們選擇以什麼字元編碼打開class檔案,這裡我們選擇Hex viewer(16進制字元編碼)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cscXTU10MJR0T0M2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL4YzM3UzM1EjMzIDNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
然後檢視第一行的前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
到線上伺服器tomcat的bin下執行./version.sh,發現用的是jdk1.7,也就是我jdk1.6編譯的class檔案現在運作在jdk1.7環境下,然後FtpClient的空構造函數在jdk1.7下是私有的,是以運作的時候代碼會報錯
rpm -qa|grep java 檢視目前伺服器有哪些jdk,我們需要jdk1.6,發現伺服器上已經有了jdk1.6
這時候我們需要找到jdk1.6的路徑,使用find -name rt.jar,這裡為什麼找rt.jar呢,因為我嘗試了很多關鍵詞,發現找不到,然後想到每個jdk中都自帶rt.jar,是以直接找這個檔案,可以迅速找到jdk的檔案路徑
找到路徑後進入tomcat的bin目錄下,vim操作catalina.sh檔案,在檔案的頭部添加一段代碼(這裡注意不要放到檔案第一行,要放到被注釋的指令的後面)
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
然後啟動服務,上傳檔案,問題解決!