zoukankan      html  css  js  c++  java
  • 深入了解Java ClassLoader、Bytecode 、ASM、cglib(II)

    三、ASM 
    我们知道Java是静态语言,而python、ruby是动态语言,Java程序一旦写好很难在运行时更改类的行为,而python、ruby可以。 
    不过基于bytecode层面上我们可以做一些手脚,来使Java程序多一些灵活性和Magic,ASM就是这样一个应用广泛的开源库。

    ASM is a Java bytecode manipulation framework. It can be used to dynamically generate stub classes or other proxy classes, 
    directly in binary form, or to dynamically modify classes at load time, i.e., just before they are loaded into the Java 
    Virtual Machine.

    ASM完成了BCELSERP同样的功能,但ASM 
    只有30多k,而后两者分别是350k和150k。apache真是越来越过气了。

    让我们来看一个ASM的简单例子Helloworld.java,它生成一个Example类和一个main方法,main方法打印"Hello world!"语句:

    代码
     
    1. import java.io.FileOutputStream;   
    2. import java.io.PrintStream;   
    3.   
    4. import org.objectweb.asm.ClassWriter;   
    5. import org.objectweb.asm.MethodVisitor;   
    6. import org.objectweb.asm.Opcodes;   
    7. import org.objectweb.asm.Type;   
    8. import org.objectweb.asm.commons.GeneratorAdapter;   
    9. import org.objectweb.asm.commons.Method;   
    10.   
    11. public class Helloworld extends ClassLoader implements Opcodes {   
    12.   
    13.   public static void main(final String args[]) throws Exception {   
    14.   
    15.     // creates a ClassWriter for the Example public class,   
    16.     // which inherits from Object   
    17.   
    18.      ClassWriter cw = new ClassWriter(0);   
    19.      cw.visit(V1_1, ACC_PUBLIC, "Example"null"java/lang/Object"null);   
    20.      MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>""()V"null,   
    21.         null);   
    22.      mw.visitVarInsn(ALOAD, 0);   
    23.      mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object""<init>""()V");   
    24.      mw.visitInsn(RETURN);   
    25.      mw.visitMaxs(11);   
    26.      mw.visitEnd();   
    27.      mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",   
    28.         "([Ljava/lang/String;)V"nullnull);   
    29.      mw.visitFieldInsn(GETSTATIC, "java/lang/System""out",   
    30.         "Ljava/io/PrintStream;");   
    31.      mw.visitLdcInsn("Hello world!");   
    32.      mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream""println",   
    33.         "(Ljava/lang/String;)V");   
    34.      mw.visitInsn(RETURN);   
    35.      mw.visitMaxs(22);   
    36.      mw.visitEnd();   
    37.     byte[] code = cw.toByteArray();   
    38.      FileOutputStream fos = new FileOutputStream("Example.class");   
    39.      fos.write(code);   
    40.      fos.close();   
    41.      Helloworld loader = new Helloworld();   
    42.      Class exampleClass = loader   
    43.          .defineClass("Example", code, 0, code.length);   
    44.      exampleClass.getMethods()[0].invoke(nullnew Object[] { null });   
    45.   
    46.     // ------------------------------------------------------------------------   
    47.     // Same example with a GeneratorAdapter (more convenient but slower)   
    48.     // ------------------------------------------------------------------------   
    49.   
    50.      cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);   
    51.      cw.visit(V1_1, ACC_PUBLIC, "Example"null"java/lang/Object"null);   
    52.      Method m = Method.getMethod("void <init> ()");   
    53.      GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, nullnull,   
    54.          cw);   
    55.      mg.loadThis();   
    56.      mg.invokeConstructor(Type.getType(Object.class), m);   
    57.      mg.returnValue();   
    58.      mg.endMethod();   
    59.      m = Method.getMethod("void main (String[])");   
    60.      mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, nullnull, cw);   
    61.      mg.getStatic(Type.getType(System.class), "out", Type   
    62.          .getType(PrintStream.class));   
    63.      mg.push("Hello world!");   
    64.      mg.invokeVirtual(Type.getType(PrintStream.class), Method   
    65.          .getMethod("void println (String)"));   
    66.      mg.returnValue();   
    67.      mg.endMethod();   
    68.      cw.visitEnd();   
    69.      code = cw.toByteArray();   
    70.      loader = new Helloworld();   
    71.      exampleClass = loader.defineClass("Example", code, 0, code.length);   
    72.      exampleClass.getMethods()[0].invoke(nullnew Object[] { null });   
    73.    }   
    74. }   

    我们看到上面的例子分别使用ASM的MethodVisitor和GeneratorAdapter两种方式来动态生成Example类并调用打印语句。

    四、cglib 
    cglib is a powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime. 
    cglib是Code Generation Library的缩写。 
    cglib依赖于ASM库。 
    Hibernate主要是利用cglib生成pojo的子类并override get方法来实现lazy loading机制,Spring则是利用cglib来实现动态代理。 
    而JDK的动态代理机制要求有接口才行,这样就强制我们的pojo实现某个接口。

    这里还是提供一个cglib的入门级的示例: 
    MyClass.java:

    代码
     
    1. public class MyClass {   
    2.   
    3.   public void print() {   
    4.      System.out.println("I'm in MyClass.print!");   
    5.    }   
    6.   
    7. }   

    Main.java: 
    代码
     
    1. import java.lang.reflect.Method;   
    2. import net.sf.cglib.proxy.Enhancer;   
    3. import net.sf.cglib.proxy.MethodInterceptor;   
    4. import net.sf.cglib.proxy.MethodProxy;   
    5.   
    6. public class Main {   
    7.   
    8.   public static void main(String[] args) {   
    9.   
    10.      Enhancer enhancer = new Enhancer();   
    11.      enhancer.setSuperclass(MyClass.class);   
    12.      enhancer.setCallback(new MethodInterceptorImpl());   
    13.      MyClass my = (MyClass) enhancer.create();   
    14.      my.print();   
    15.    }   
    16.   
    17.   private static class MethodInterceptorImpl implements MethodInterceptor {   
    18.     public Object intercept(Object obj, Method method, Object[] args,   
    19.          MethodProxy proxy) throws Throwable {   
    20.       // log something   
    21.        System.out.println(method + " intercepted!");   
    22.   
    23.        proxy.invokeSuper(obj, args);   
    24.       return null;   
    25.      }   
    26.    }   
    27. }   

    打印结果为: 
    代码
     
    1. public void MyClass.print() intercepted!   
    2. I'm in MyClass.print!   

    这个示例就基本上实现了日志AOP的功能
  • 相关阅读:
    并不对劲的CF1236D&E:Alice&Doll&UnfairGame
    并不对劲的CF1194E:Count The Rectangles
    并不对劲的CF1239B&C&D Programming Task in the Train to Catowice City
    并不对劲的初赛蒙猜凑思路
    并不对劲的CF1237D&E:Balanced Playlist and Binary Search Trees
    并不对劲的???
    并不对劲的P5589
    (简单) POJ 1511 Invitation Cards,SPFA。
    (简单) POJ 3159 Candies,Dijkstra+差分约束。
    (简单) POJ 2502 Subway,Dijkstra。
  • 原文地址:https://www.cnblogs.com/balaamwe/p/2391997.html
Copyright © 2011-2022 走看看