用 BCEL 设计字节码: 直接在方法的调用处添加方法
2009-09-23 00:00:00 来源:WEB开发网main这个调用的代码或者使用INVOKEXXXX指令实现,或者把这些调用方法的字节码指令序列加入到main的指令序列当中来实现,直接加的话可能自己事先写的方法的局部变量与main方法的局部变量会相同,而且涉及到所加的指令序列使用局部变量的问题,比如加的iload_0,istore_2就会引用现在方法的局部变量,但是现在的局部变量根本就不是这种指令所对应的类型
。所以还是使用方法调用比较方便
import java.io.FileOutputStream;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantMethodref;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LocalVariableGen;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;
public class BCELTiming3 {
/**//*
* 扫描StringBuilder的各个方法的指令序列,在其中找Invokexxxx指令,
* 看此指令在常量池中引用的方法引用是否是要其前后加代码的方法
* 方法所在的类要一致,方法的名称要一致,方法的签名要一致
*
*/
/** *//**
*
* @param cgen 要被解析的类class文件
* @param classname 要被修改的方法所在的类名称,若有包名,则为java/lang/Object类似的
* @param methodname 要被修改的方法的名称
* @param methodSignature 要被修改的方法的签名
*/
private static void modifyWrapper(ClassGen cgen,String classname,String methodname,String methodSignature){
InstructionFactory ifact = new InstructionFactory(cgen);
ConstantPoolGen pgen = cgen.getConstantPool();
ConstantPool pool = pgen.getConstantPool();
String cname = cgen.getClassName();
Method[] methods = cgen.getMethods();
for(int i=0;i<methods.length;i++){
Method tempMethod = methods[i];
MethodGen tempMethodGen = new MethodGen(tempMethod,cname,pgen);
InstructionList tempList = tempMethodGen.getInstructionList();
tempList.iterator();
Instruction[] tempInstructions = tempList.getInstructions();
InstructionHandle[] tempInHandles = tempList.getInstructionHandles();
for(int j=0;j<tempInHandles.length;j++){
InstructionHandle ihandle = tempInHandles[j];
Instruction nowInstruction = ihandle.getInstruction();
if(nowInstruction.getOpcode()==Constants.INVOKEVIRTUAL){
INVOKEVIRTUAL invokeVirtual = (INVOKEVIRTUAL)nowInstruction;
ConstantMethodref cmr = (ConstantMethodref)pgen.getConstant(invokeVirtual.getIndex());
ConstantClass cc = (ConstantClass)pgen.getConstant(cmr.getClassIndex());
String nowClassName = cc.getBytes(pgen.getConstantPool());
ConstantNameAndType cnt = (ConstantNameAndType)pgen.getConstant(cmr.getNameAndTypeIndex());
String nowMethodName = cnt.getName(pgen.getConstantPool());
String nowMethodSignature = cnt.getSignature(pgen.getConstantPool());
//判断此方法的所属的类,方法的名称,方法的签名是否与所要加的一致(I)Ljava/lang/String;
if(nowClassName.equals(classname) && nowMethodName.equals(methodname) && nowMethodSignature.equals(methodSignature)){
cgen.removeMethod(tempMethodGen.getMethod());
//找到此方法在list的位置
InstructionList beforeList = new InstructionList();
//先加一个局部变量保存starttime的值
LocalVariableGen lvg = tempMethodGen.addLocalVariable("starttime", Type.LONG, null, null);
beforeList.append(ifact.createInvoke("ToolUtil", "printStart", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC));
beforeList.append(InstructionFactory.createStore(Type.LONG, lvg.getIndex()));
tempList.insert(ihandle.getPrev().getPrev(), beforeList);
//加方法后的代码
InstructionList afterList = new InstructionList();
afterList.append(ifact.createConstant(methodname));
afterList.append(ifact.createLoad(Type.LONG, lvg.getIndex()));
afterList.append(ifact.createInvoke("ToolUtil", "printEnd", Type.VOID, new Type[]{Type.STRING,Type.LONG}, Constants.INVOKESTATIC));
tempList.insert(ihandle.getNext().getNext(), afterList);
//finalize the construted method
tempMethodGen.stripAttributes(false);
tempMethodGen.setMaxStack();
tempMethodGen.setMaxLocals();
cgen.addMethod(tempMethodGen.getMethod());
System.out.println(tempMethodGen.getInstructionList());
System.out.println();
System.out.println();
}
}
}
// tempList.setPositions();
// tempList.findHandle(pos);
}
}
/** *//**
* @param args
*/
public static void main(String[] args) {
args[0]="D:\\java to eclipse\\javaeclipsestudy\\workspace\\BCELTest\\bin\\StringBuilder.class";
if(args.length==1 && args[0].endsWith(".class")){
try{
JavaClass jclas = new ClassParser(args[0]).parse();
ClassGen cgen = new ClassGen(jclas);
modifyWrapper(cgen,"StringBuilder","buildString","(I)Ljava/lang/String;");
cgen.getJavaClass().dump(args[0]);
}catch(Exception e){
e.printStackTrace();
}
}else{
System.out.println("usage: class-file");
}
}
}
更多精彩
赞助商链接