您的位置:首页 > 编程语言 > Java开发

用 javassist 来修改 class 文件

2013-03-07 00:28 190 查看
  在一个老项目中,不知是哪位牛人写的程序,调用了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 是一个比较常见的包,网上一搜就能搜到,这里就不在添加了。

来自为知笔记(Wiz)[Attachments]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: