用 javassist 來修改 class 文件


  在一個老項目中,不知是哪位牛人寫的程序,調用了FileInputStream,但是沒有關閉文件流。而這個地方是最常用的一個地方,導致系統運行一段時間之后內存耗盡,報文件句柄數過多的錯誤。
  處理這種問題,如果有源碼,加上關閉文件流的操作即可。但是,由於公司的源碼管理得不好,這個項目的源碼已經丟失了, 沒有源碼,只能反編譯得到源碼加上關閉文件流的操作再編譯一次,這樣編譯出來的class文件跟原來的class文件里面的一些變量有差異,替換之后會引起另外一個更嚴重的問題:鏈接走正常路線的時候可以訪問,但是走通過F5負載均衡的時候就不能訪問了。
  這個問題相當的棘手,因為以替換class文件,就會引起更嚴重的問題,但是文件句柄不釋放的問題也很重要。至於"通過F5負載均衡的時候為什么不能訪問"這個問題,由於對F5負載均衡不了解,通過解決這個問題來解決句柄問題看起來很不可能。於是想到了用開源的jar包來直接修改class文件,直接在class文件中直接添加將文件流關閉的操作。
  在網上查資料之后有兩種方式來編輯class文件:classEdit和javassist。我用了javassist來修改class文件,在class文件中添加關閉文件流的操作之后,重新生成了一個class文件,用這個class文件和修改前的class文件反編譯對比,非常的完美,就只比修改前的文件多了關閉文件流的操作,其他的地方一模一樣。
 
    修改calss文件的示例代碼如下:
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
 
public class Test {
 
    public static void main(String[] args) throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        // 必須將class文件放在這個工程編譯后的class文件中,路徑也對應起來
        CtClass ctClass = classPool.get("com.ambitionstone.esa2000.pki.AZTPkiServlet");
        
        //設置方法需要的參數,一定要能匹配起來,而且必須引入這些參數類的包
        CtClass[] param = new CtClass[4] ;                
        param[0] = classPool.get("javax.servlet.http.HttpServletRequest") ;
        param[1] = classPool.get("javax.servlet.http.HttpServletResponse") ;
        param[2] = classPool.get("int") ;
        param[3] = classPool.get("java.lang.String") ;
        
        // 找到需要修改的行所在的方法
        CtMethod  method = ctClass.getDeclaredMethod("doOnlineValidate", param);
        
        // 在這個方法的182行添加關閉文件流的方法
        method.insertAt(182, "fin.close();");
        
        // 將文件寫到指定的目錄,生成之后在test\com\ambitionstone\esa2000\pki\AZTPkiServlet\這個文件夾下面可以找到編譯后的類
        ctClass.writeFile("D:\\test") ;
    }
}

javassist.jar 是一個比較常見的包,網上一搜就能搜到,這里就不在添加了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM