深入瞭解Java ClassLoader、Bytecode 、ASM、cglib(II)

來源:互聯網
上載者:User

三、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完成了BCEL和SERP同樣的功能,但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(1, 1);   
  26.      mw.visitEnd();   
  27.      mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",   
  28.         "([Ljava/lang/String;)V", null, null);   
  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(2, 2);   
  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(null, new 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, null, null,   
  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, null, null, 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(null, new 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的功能

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.