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

摘要:
代码导入java。io.FileOutputStream;导入org.objectweb.asm.ClassWriter;导入org.objectweb.asm.Type;“(Ljava/lang/String;mw.visitInsn(RETURN);mw.visitEnd();

三、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的功能

免责声明:文章转载自《深入了解Java ClassLoader、Bytecode 、ASM、cglib(II)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用子查询可提升 COUNT DISTINCT 速度 50 倍MFC文件操作下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

『MXNet』第十弹_物体检测SSD

全流程地址 一、辅助API介绍 mxnet.image.ImageDetIter 图像检测迭代器, from mxnet import image from mxnet import nd data_shape = 256 batch_size = 32 rgb_mean = nd.array([123, 117, 104]) def g...

[开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [一] 初衷与架构设计

[DotnetSpider 系列目录] 一、初衷与架构设计 二、基本使用 三、配置式爬虫 四、JSON数据解析与配置系统 五、如何做全站采集 为什么要造轮子 同学们可以去各大招聘网站查看一下爬虫工程师的要求,大多是招JAVA、PYTHON,甚至于还有NODEJS,C++;再或者去开源中国查询C#的爬虫项目,仅有几个非常简单或是几年没有更新的项目。 而单...

动态任务定义和任务链

1、以下内容写在 build.gradle 文件中 task helloworld << { test()} def test(){ ant.echo(message:'repeat after me...')             ##隐含对ant任务使用} 3.times {                                ...

VC下动态库dll,静态库lib的编写和使用方法

在一些项目中,考虑到系统的安全性和稳定性,经常要封装一些DLL或者LIB库供别人使用,那么怎么制作DLL或者LIB文件呢?今天特酷吧根据自己的实际情况给大家讲解下基本的制作方法。以下是我亲自操作的记录:1,动态库dll的编写方法:新建一个动态链接库:填好工程名称即可选择工程类型,如果没有特别的要求,选择一个空工程即可。会看到这里和标准的控制台工程一样,没有任...

python:动态参数*args

动态参数   顾名思义,动态参数就是传入的参数的个数是动态的,可以是1个、2个到任意个,还可以是0个。在不需要的时候,你完全可以忽略动态函数,不用给它传递任何值。 Python的动态参数有两种,分别是*args和**kwargs,这里面的关键是一个和两个星号的区别,而不是args和kwargs在名字上的区别,实际上你可以使用*any或**whatever的...

c#使用反射调用类型成员示例

在实际的工作中直接使用反射的机会比较少,有印象的就是一次自己做的WinForms小工具的时候利用反射来动态获取窗体上的每个控件,并且为必要的控件动态添加注册事件。因为刚入职新公司,为了更快的了解公司的业务、和开发习惯,先和现在公司同事一起修改现有系统的一些小Bug。在Tester提交的Bug中有一个是对GridView进行动态的排序——点击一个列时使用该列...