Java字节码框架asm快速入门

时间:2021-03-12 17:05:52

 asm是一个java的字节码框架,它能被用来动态生成类或者增强既有类的功能。
一般asm的应用场景主要在aop上,比如Spring在底层就是用了asm,但asm不仅仅是只能在aop方面发挥它强大的能力,比如你现在要写一个rpc框架,可能会在序列化对象上犯难,使用java的序列化机制?有点慢;json?(比如阿里的大神搞的fastjson性能就很好),但我要序列化的对象很简单,没有嵌套对象,不需要深拷贝,并且我并不想按照json的格式来
我的计划是将对象拼成如下格式的字符串:
Java代码 Java字节码框架asm快速入门 Java字节码框架asm快速入门Java字节码框架asm快速入门
  1. fieldName1,Type1,value1;fieldName2,Type2,value2;fieldName3,Type3,value3;fieldName4,Type4,value4;...;

用反射实现的代码大致是这样:
Java代码 Java字节码框架asm快速入门 Java字节码框架asm快速入门Java字节码框架asm快速入门
  1. for (Map.Entry<String, Pair<String, Field>> iter : argFields.entrySet()) {
  2. fieldName = iter.getKey(); // 名
  3. pair = iter.getValue();
  4. fieldType = pair.getKey(); // 类型
  5. fieldValue = pair.getValue().get(event); // 值(反射)
  6. if (fieldValue instanceof Date) {
  7. sBuilder.append(fieldName).append(",").append(fieldType).append(",").append(((Date) fieldValue).getTime()).append(";");
  8. } else {
  9. sBuilder.append(fieldName).append(",").append(fieldType).append(",").append(fieldValue).append(";");
  10. }
  11. }

速度还可以,不过我觉得还可以更快,于是我想到了用asm代替反射,由于我个人对字节码的指令只是略知一二(都是从《深入java虚拟机》一书来的些理论知识),所以用那200来个字节码指令直接写一个我想要的类实在有点难度,于是我先用java写了一个我想要的类,然后用
Java代码 Java字节码框架asm快速入门 Java字节码框架asm快速入门Java字节码框架asm快速入门
  1. javap -verbose XXX

反编译了它,然后照着反编译出来的字节码指令以及注释一步一步最后完成了一个类

下面这个类是我想要的类,我先用java完成了它
Java代码 Java字节码框架asm快速入门 Java字节码框架asm快速入门Java字节码框架asm快速入门
  1. public StringBuilder write(Event event) throws IOException {
  2. GNSEvent obj = (GNSEvent) event;
  3. StringBuilder sBuilder = new StringBuilder(256);
  4. sBuilder.append("cityCode").append(",").append("java.lang.String").append(obj.getCityCode());
  5. // obj循环序列化obj的所有属性
  6. return sBuilder;
  7. }


用javap反编译它,得到下面有用的信息:
Java代码 Java字节码框架asm快速入门 Java字节码框架asm快速入门Java字节码框架asm快速入门
  1. public com.futurefleet.framework.serialization.Serializer_1GNSEvent();
  2. Code:
  3. Stack=1, Locals=1, Args_size=1
  4. 0: aload_0
  5. 1: invokespecial #10;//Method java/lang/Object."<init>":()V
  6. 4: return
  7. LineNumberTable:
  8. line 16: 0
  9. LocalVariableTable:
  10. Start Length Slot Name Signature
  11. 0 5 0 this Lcom/futurefleet/framework/serialization/Serializer_1GNSEvent;
  12. public java.lang.StringBuilder write(com.futurefleet.framework.base.event.Event)throws java.io.IOException;
  13. Exceptions:
  14. throws java.io.IOException Code:
  15. Stack=3, Locals=4, Args_size=2
  16. 0: aload_1
  17. 1: checkcast #21; //class com/futurefleet/gateway/event/GNSEvent
  18. 4: astore_2
  19. 5: new #23;//class java/lang/StringBuilder
  20. 8: dup
  21. 9: sipush 256
  22. 12: invokespecial #25;//Method java/lang/StringBuilder."<init>":(I)V
  23. 15: astore_3
  24. 16: aload_3
  25. 17: ldc #28; //String cityCode
  26. 19: invokevirtual #30;//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  27. 22: ldc #34; //String ,
  28. 24: invokevirtual #30;//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  29. 27: ldc #36; //String java.lang.String
  30. 29: invokevirtual #30;//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  31. 32: aload_2
  32. 33: invokevirtual #38;//Method com/futurefleet/gateway/event/GNSEvent.getCityCode:()Ljava/lang/String;
  33. 36: invokevirtual #30;//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  34. 39: pop
  35. 40: aload_3
  36. 41: areturn