java字节码操作

来源:互联网 发布:家用急救包淘宝 编辑:程序博客网 时间:2024/05/14 11:02

动态编译Java源文件:
主要作用就是可以动态的编译生成一些class文件,源码你可以自己拼写。

demo:

package com.partner4java.javacompiler;import java.io.IOException;import java.net.URI;import java.net.URISyntaxException;import java.util.Arrays;import javax.tools.JavaCompiler;import javax.tools.JavaCompiler.CompilationTask;import javax.tools.JavaFileObject;import javax.tools.SimpleJavaFileObject;import javax.tools.StandardJavaFileManager;import javax.tools.ToolProvider;/** * 动态编译 *  */public class CompilerTest {public static void main(String[] args) throws Exception {// 类的文本String source = "public class Main { public static void main(String[] args) {System.out.println(\"Hello World! \");} }";// 为 JavaFileObject 中的大多数方法提供简单实现。应子类化此类并用作 JavaFileObject 实现的基础。// 子类可以重写此类任意方法的实现和规范,只要不违背 JavaFileObject 的常规协定。SimpleJavaFileObject sourceObject = new CompilerTest.StringSourceJavaObject("Main", source);// 为查找工具提供者提供方法,例如,编译器的提供者。// 获取此平台提供的 Java 编程语言编译器。JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();// 为此工具获取一个标准文件管理器实现的新实例。StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);// 使用给定组件和参数创建编译任务的 future。CompilationTask task = compiler.getTask(null, fileManager, null, null,null, fileObjects);boolean result = task.call();if (result) {System.out.println(" 编译成功。");}}/** * 主要指定了编译的存储位置和格式 * */static class StringSourceJavaObject extends SimpleJavaFileObject {private String content = null;public StringSourceJavaObject(String name, String content)throws URISyntaxException {super(URI.create("string:///" + name.replace('.', '/')+ Kind.SOURCE.extension), Kind.SOURCE);this.content = content;}public CharSequence getCharContent(boolean ignoreEncodingErrors)throws IOException {return content;}}}

是在字节码生成之后对其修改,增强其功能。

CGLIB hellowrld:
http://blog.csdn.net/partner4java/article/details/7627527

基本都类似于这种做法。



java.lang.instrument:
提供允许 Java 编程语言代理检测运行在 JVM 上的程序的服务。

jdk提供的合法的AOP

两个比较牛B的技术帖子:
http://www.ibm.com/developerworks/cn/java/j-lo-instrumentation/
http://www.ibm.com/developerworks/cn/java/j-cwt06075/

http://blog.sina.com.cn/s/blog_605f5b4f0100qfvc.html

package com.partner4java.instrument;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.lang.instrument.Instrumentation;import java.security.ProtectionDomain;public class MyLog implements ClassFileTransformer {    // 方法。通过这个方法,代理可以得到虚拟机载入的类的字节码(通过 classfileBuffer    // 参数)。代理的各种功能一般是通过操作这一串字节码得以实现的。同时还需要提供一个公共的静态方法:    @Override    public byte[] transform(ClassLoader loader, String className,            Class<?> classBeingRedefined, ProtectionDomain protectionDomain,            byte[] classfileBuffer) throws IllegalClassFormatException {        // transform 函数的最后,返回 null 值,表示不需要进行类字节码的转化        System.out.println("Hello,\t" + className);        return null;    }    // 一般会在这个方法中创建一个代理对象,通过参数 inst 的 addTransformer()    // 方法,将创建的代理对象再传递给虚拟机。这个方法是一个入口方法,有点类似于一般类的 main 方法。    public static void premain(String agentArgs, Instrumentation inst) {        // options 参数是通过命令行传递进来的,类似于调用 main 函数时传递的参数。被传递进来的命令行参数是一个完整的字符串,不同于        // main 方法,该字符串的解析完全由代理自己负责。        // 定制完代理的行为之后,创建一个 MyLog 代理的实例,将该实例传递给虚拟机。        if (agentArgs != null) {            System.out.printf("  I've been called with options: \"%s\"\n",                    agentArgs);        } else            System.out.println("  I've been called with no options.");        inst.addTransformer(new MyLog());    }}



maven打包如com.partner4java.javautil.codemanage-0.0.1-SNAPSHOT.jar,然后
C:\Users\Administrator>java -javaagent:E:\partner4java\code\workspace\java字节码
操作\target\com.partner4java.javautil.codemanage-0.0.1-SNAPSHOT.jar="hello world
" com.partner4java.javacompiler.CompilerTest


打印运行时间demo:
com.partner4java.instrument.Timing

package com.partner4java.instrument;import java.io.IOException;import java.io.ByteArrayOutputStream;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.lang.instrument.Instrumentation;import org.apache.bcel.Constants;import org.apache.bcel.classfile.ClassParser;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.InstructionConstants;import org.apache.bcel.generic.InstructionFactory;import org.apache.bcel.generic.InstructionList;import org.apache.bcel.generic.MethodGen;import org.apache.bcel.generic.ObjectType;import org.apache.bcel.generic.PUSH;import org.apache.bcel.generic.Type;public class Timing implements ClassFileTransformer {private String methodName;private Timing(String methodName) {this.methodName = methodName;System.out.println(methodName);}public byte[] transform(ClassLoader loader, String className, Class cBR,java.security.ProtectionDomain pD, byte[] classfileBuffer)throws IllegalClassFormatException {try {ClassParser cp = new ClassParser(new java.io.ByteArrayInputStream(classfileBuffer), className + ".java");JavaClass jclas = cp.parse();ClassGen cgen = new ClassGen(jclas);Method[] methods = jclas.getMethods();int index;for (index = 0; index < methods.length; index++) {if (methods[index].getName().equals(methodName)) {break;}}if (index < methods.length) {addTimer(cgen, methods[index]);ByteArrayOutputStream bos = new ByteArrayOutputStream();cgen.getJavaClass().dump(bos);return bos.toByteArray();}System.err.println("Method " + methodName + " not found in "+ className);System.exit(0);} catch (IOException e) {System.err.println(e);System.exit(0);}return null; // No transformation required}private static void addTimer(ClassGen cgen, Method method) {// set up the construction toolsInstructionFactory ifact = new InstructionFactory(cgen);InstructionList ilist = new InstructionList();ConstantPoolGen pgen = cgen.getConstantPool();String cname = cgen.getClassName();MethodGen wrapgen = new MethodGen(method, cname, pgen);wrapgen.setInstructionList(ilist);// rename a copy of the original methodMethodGen methgen = new MethodGen(method, cname, pgen);cgen.removeMethod(method);String iname = methgen.getName() + "_timing";methgen.setName(iname);cgen.addMethod(methgen.getMethod());Type result = methgen.getReturnType();// compute the size of the calling parametersType[] parameters = methgen.getArgumentTypes();int stackIndex = methgen.isStatic() ? 0 : 1;for (int i = 0; i < parameters.length; i++) {stackIndex += parameters[i].getSize();}// save time prior to invocationilist.append(ifact.createInvoke("java.lang.System","currentTimeMillis", Type.LONG, Type.NO_ARGS,Constants.INVOKESTATIC));ilist.append(InstructionFactory.createStore(Type.LONG, stackIndex));// call the wrapped methodint offset = 0;short invoke = Constants.INVOKESTATIC;if (!methgen.isStatic()) {ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0));offset = 1;invoke = Constants.INVOKEVIRTUAL;}for (int i = 0; i < parameters.length; i++) {Type type = parameters[i];ilist.append(InstructionFactory.createLoad(type, offset));offset += type.getSize();}ilist.append(ifact.createInvoke(cname, iname, result, parameters,invoke));// store result for return laterif (result != Type.VOID) {ilist.append(InstructionFactory.createStore(result, stackIndex + 2));}// print time required for method callilist.append(ifact.createFieldAccess("java.lang.System", "out",new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));ilist.append(InstructionConstants.DUP);ilist.append(InstructionConstants.DUP);String text = "Call to method " + methgen.getName() + " took ";ilist.append(new PUSH(pgen, text));ilist.append(ifact.createInvoke("java.io.PrintStream", "print",Type.VOID, new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));ilist.append(ifact.createInvoke("java.lang.System","currentTimeMillis", Type.LONG, Type.NO_ARGS,Constants.INVOKESTATIC));ilist.append(InstructionFactory.createLoad(Type.LONG, stackIndex));ilist.append(InstructionConstants.LSUB);ilist.append(ifact.createInvoke("java.io.PrintStream", "print",Type.VOID, new Type[] { Type.LONG }, Constants.INVOKEVIRTUAL));ilist.append(new PUSH(pgen, " ms."));ilist.append(ifact.createInvoke("java.io.PrintStream", "println",Type.VOID, new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));// return result from wrapped method callif (result != Type.VOID) {ilist.append(InstructionFactory.createLoad(result, stackIndex + 2));}ilist.append(InstructionFactory.createReturn(result));// finalize the constructed methodwrapgen.stripAttributes(true);wrapgen.setMaxStack();wrapgen.setMaxLocals();cgen.addMethod(wrapgen.getMethod());ilist.dispose();}public static void premain(String options, Instrumentation ins) {if (options != null) {ins.addTransformer(new Timing(options));} else {System.out.println("Usage: java -javaagent:Timing.jar=\"class:method\"");System.exit(0);}}}


原创粉丝点击