在java程序开发过程当中,没有源码是很常见的事,咱们能够经过IDE(Eclipse须要配置jad.exe、IDEA)自动的将class文件反编译为java文件。或者咱们借助于其余工具(jd-gui, luyten)来直接的对整个jar包进行反编译。反编译工具是如何作到代码反编译的呢?若是是在生产环境下帮助用户解决问题时,是没有这些工具的,该怎么办呢?java
在开发apm,jprofiler这样的工具时,spring团队在实现aop (例如interceptor),一般都会经过字节码 技术对已有代码进行改造,以达到对代码进行监控,改造工做。那么又是如何将字节码指令嵌入的呢?web
要想了解这些东西,不学习class文件如何看,不了解相关字节码指令是很难解决上面的问题的。spring
在了解class文件以前,先来看一个例子:这是一个真实的需求。不一样的机器时间没有使用NTP服务进行时间同步。在这样的一个环境下,各个机器的数据都以入库(若是的数据是机器自身的时间),如今要查看某个机器当前时间的数据,或者最近20分钟的数据。为了解决该问题,作了一个机器时间计算工具:jvm
实现的源码以下:ide
public class RelativeTime { private String machineId; private long delta; public RelativeTime() { } public RelativeTime(final String machineId, final long time) { this.machineId = machineId; final long now = System.currentTimeMillis(); this.delta = now - time; } public String getMachineId() { return this.machineId; } public void setMachineId(final String machineId) { this.machineId = machineId; } public long getDelta() { return this.delta; } public void setDelta(final long delta) { this.delta = delta; } }
import java.util.concurrent.*; public class RelativeTimeManager { private final ConcurrentHashMap<String, RelativeTime> cache; public RelativeTimeManager() { this.cache = new ConcurrentHashMap<String, RelativeTime>(); } public void add(final String machineId, final long machineTime) { if (machineId != null) { final RelativeTime t = new RelativeTime(machineId, machineTime); this.add(t); } } public void add(final RelativeTime time) { if (time != null) { this.cache.put(time.getMachineId(), time); } } public void addIfAbsent(final String machineId, final long machineTime) { if (machineId != null && machineTime > 0L) { final RelativeTime t = new RelativeTime(machineId, machineTime); this.addIfAbsent(t); } } public void addIfAbsent(final RelativeTime time) { this.cache.putIfAbsent(time.getMachineId(), time); } public void remove(final String machineId) { if (machineId != null) { this.cache.remove(machineId); } } public boolean hasMachine(final String machineId) { return machineId != null && this.cache.get(machineId) != null; } public long getDeltaTime(final String machineId) { return this.cache.get(machineId).getDelta(); } public long getMachineCurrentTime(final String machineId) { return this.getMachineRelativeTime(machineId, System.currentTimeMillis()); } public long getMachineRelativeTime(final String machineId, final long time) { if (this.hasMachine(machineId)) { final long delta = this.getDeltaTime(machineId); return time - delta; } return time; } }
先来解决上面提出的第一个问题,没有反编译工具的状况下如何查看java类:工具
在java_home/bin目录下,有这样一个工具:javap,使用它便可查看class文件内容。性能
对上述两个类分别执行 javap -l -v -p RelativeTime.class (javap -l -v -p RelativeTimeManager.class) 命令后以下:学习
RelativeTime:ui
Classfile /C:/Users/User/Desktop/webgate-commons/com/bes/webgate/common/clock/RelativeTime.class Last modified 2017-11-10; size 1005 bytes MD5 checksum eff96db3a12a575b2a4ebc1272b896e4 Compiled from "RelativeTime.java" public class com.bes.webgate.common.clock.RelativeTime SourceFile: "RelativeTime.java" minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#31 // java/lang/Object."<init>":()V #2 = Fieldref #5.#32 // com/bes/webgate/common/clock/RelativeTime.machineId:Ljava/lang/String; #3 = Methodref #33.#34 // java/lang/System.currentTimeMillis:()J #4 = Fieldref #5.#35 // com/bes/webgate/common/clock/RelativeTime.delta:J #5 = Class #36 // com/bes/webgate/common/clock/RelativeTime #6 = Class #37 // java/lang/Object #7 = Utf8 machineId #8 = Utf8 Ljava/lang/String; #9 = Utf8 delta #10 = Utf8 J #11 = Utf8 <init> #12 = Utf8 ()V #13 = Utf8 Code #14 = Utf8 LineNumberTable #15 = Utf8 LocalVariableTable #16 = Utf8 this #17 = Utf8 Lcom/bes/webgate/common/clock/RelativeTime; #18 = Utf8 (Ljava/lang/String;J)V #19 = Utf8 time #20 = Utf8 now #21 = Utf8 getMachineId #22 = Utf8 ()Ljava/lang/String; #23 = Utf8 setMachineId #24 = Utf8 (Ljava/lang/String;)V #25 = Utf8 getDelta #26 = Utf8 ()J #27 = Utf8 setDelta #28 = Utf8 (J)V #29 = Utf8 SourceFile #30 = Utf8 RelativeTime.java #31 = NameAndType #11:#12 // "<init>":()V #32 = NameAndType #7:#8 // machineId:Ljava/lang/String; #33 = Class #38 // java/lang/System #34 = NameAndType #39:#26 // currentTimeMillis:()J #35 = NameAndType #9:#10 // delta:J #36 = Utf8 com/bes/webgate/common/clock/RelativeTime #37 = Utf8 java/lang/Object #38 = Utf8 java/lang/System #39 = Utf8 currentTimeMillis { private java.lang.String machineId; flags: ACC_PRIVATE private long delta; flags: ACC_PRIVATE public com.bes.webgate.common.clock.RelativeTime(); flags: ACC_PUBLIC LineNumberTable: line 20: 0 line 22: 4 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 20: 0 line 22: 4 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; public com.bes.webgate.common.clock.RelativeTime(java.lang.String, long); flags: ACC_PUBLIC LineNumberTable: line 24: 0 line 25: 4 line 26: 9 line 27: 14 line 28: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 this Lcom/bes/webgate/common/clock/RelativeTime; 0 23 1 machineId Ljava/lang/String; 0 23 2 time J 14 9 4 now J Code: stack=5, locals=6, args_size=3 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: aload_1 6: putfield #2 // Field machineId:Ljava/lang/String; 9: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J 12: lstore 4 14: aload_0 15: lload 4 17: lload_2 18: lsub 19: putfield #4 // Field delta:J 22: return LineNumberTable: line 24: 0 line 25: 4 line 26: 9 line 27: 14 line 28: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 this Lcom/bes/webgate/common/clock/RelativeTime; 0 23 1 machineId Ljava/lang/String; 0 23 2 time J 14 9 4 now J public java.lang.String getMachineId(); flags: ACC_PUBLIC LineNumberTable: line 31: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #2 // Field machineId:Ljava/lang/String; 4: areturn LineNumberTable: line 31: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; public void setMachineId(java.lang.String); flags: ACC_PUBLIC LineNumberTable: line 35: 0 line 36: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/bes/webgate/common/clock/RelativeTime; 0 6 1 machineId Ljava/lang/String; Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #2 // Field machineId:Ljava/lang/String; 5: return LineNumberTable: line 35: 0 line 36: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/bes/webgate/common/clock/RelativeTime; 0 6 1 machineId Ljava/lang/String; public long getDelta(); flags: ACC_PUBLIC LineNumberTable: line 39: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; Code: stack=2, locals=1, args_size=1 0: aload_0 1: getfield #4 // Field delta:J 4: lreturn LineNumberTable: line 39: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; public void setDelta(long); flags: ACC_PUBLIC LineNumberTable: line 43: 0 line 44: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/bes/webgate/common/clock/RelativeTime; 0 6 1 delta J Code: stack=3, locals=3, args_size=2 0: aload_0 1: lload_1 2: putfield #4 // Field delta:J 5: return LineNumberTable: line 43: 0 line 44: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/bes/webgate/common/clock/RelativeTime; 0 6 1 delta J }
RelativeTimeManager:this
Classfile /C:/Users/User/Desktop/webgate-commons/com/bes/webgate/common/clock/RelativeTimeManager.class Last modified 2017-11-10; size 2352 bytes MD5 checksum 3475ce705b7622e212b5630a59413264 Compiled from "RelativeTimeManager.java" public class com.bes.webgate.common.clock.RelativeTimeManager SourceFile: "RelativeTimeManager.java" minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #20.#56 // java/lang/Object."<init>":()V #2 = Class #57 // java/util/concurrent/ConcurrentHashMap #3 = Methodref #2.#56 // java/util/concurrent/ConcurrentHashMap."<init>":()V #4 = Fieldref #19.#58 // com/bes/webgate/common/clock/RelativeTimeManager.cache:Ljava/util/concurrent/ConcurrentHashMap; #5 = Class #59 // com/bes/webgate/common/clock/RelativeTime #6 = Methodref #5.#60 // com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V #7 = Methodref #19.#61 // com/bes/webgate/common/clock/RelativeTimeManager.add:(Lcom/bes/webgate/common/clock/RelativeTime;)V #8 = Methodref #5.#62 // com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String; #9 = Methodref #2.#63 // java/util/concurrent/ConcurrentHashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; #10 = Methodref #19.#64 // com/bes/webgate/common/clock/RelativeTimeManager.addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V #11 = Methodref #2.#65 // java/util/concurrent/ConcurrentHashMap.putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; #12 = Methodref #2.#66 // java/util/concurrent/ConcurrentHashMap.remove:(Ljava/lang/Object;)Ljava/lang/Object; #13 = Methodref #2.#67 // java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object; #14 = Methodref #5.#68 // com/bes/webgate/common/clock/RelativeTime.getDelta:()J #15 = Methodref #69.#70 // java/lang/System.currentTimeMillis:()J #16 = Methodref #19.#71 // com/bes/webgate/common/clock/RelativeTimeManager.getMachineRelativeTime:(Ljava/lang/String;J)J #17 = Methodref #19.#72 // com/bes/webgate/common/clock/RelativeTimeManager.hasMachine:(Ljava/lang/String;)Z #18 = Methodref #19.#73 // com/bes/webgate/common/clock/RelativeTimeManager.getDeltaTime:(Ljava/lang/String;)J #19 = Class #74 // com/bes/webgate/common/clock/RelativeTimeManager #20 = Class #75 // java/lang/Object #21 = Utf8 cache #22 = Utf8 Ljava/util/concurrent/ConcurrentHashMap; #23 = Utf8 Signature #24 = Utf8 Ljava/util/concurrent/ConcurrentHashMap<Ljava/lang/String;Lcom/bes/webgate/common/clock/RelativeTime;>; #25 = Utf8 <init> #26 = Utf8 ()V #27 = Utf8 Code #28 = Utf8 LineNumberTable #29 = Utf8 LocalVariableTable #30 = Utf8 this #31 = Utf8 Lcom/bes/webgate/common/clock/RelativeTimeManager; #32 = Utf8 add #33 = Utf8 (Ljava/lang/String;J)V #34 = Utf8 t #35 = Utf8 Lcom/bes/webgate/common/clock/RelativeTime; #36 = Utf8 machineId #37 = Utf8 Ljava/lang/String; #38 = Utf8 machineTime #39 = Utf8 J #40 = Utf8 StackMapTable #41 = Utf8 (Lcom/bes/webgate/common/clock/RelativeTime;)V #42 = Utf8 time #43 = Utf8 addIfAbsent #44 = Utf8 remove #45 = Utf8 (Ljava/lang/String;)V #46 = Utf8 hasMachine #47 = Utf8 (Ljava/lang/String;)Z #48 = Utf8 getDeltaTime #49 = Utf8 (Ljava/lang/String;)J #50 = Utf8 getMachineCurrentTime #51 = Utf8 getMachineRelativeTime #52 = Utf8 (Ljava/lang/String;J)J #53 = Utf8 delta #54 = Utf8 SourceFile #55 = Utf8 RelativeTimeManager.java #56 = NameAndType #25:#26 // "<init>":()V #57 = Utf8 java/util/concurrent/ConcurrentHashMap #58 = NameAndType #21:#22 // cache:Ljava/util/concurrent/ConcurrentHashMap; #59 = Utf8 com/bes/webgate/common/clock/RelativeTime #60 = NameAndType #25:#33 // "<init>":(Ljava/lang/String;J)V #61 = NameAndType #32:#41 // add:(Lcom/bes/webgate/common/clock/RelativeTime;)V #62 = NameAndType #76:#77 // getMachineId:()Ljava/lang/String; #63 = NameAndType #78:#79 // put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; #64 = NameAndType #43:#41 // addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V #65 = NameAndType #80:#79 // putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; #66 = NameAndType #44:#81 // remove:(Ljava/lang/Object;)Ljava/lang/Object; #67 = NameAndType #82:#81 // get:(Ljava/lang/Object;)Ljava/lang/Object; #68 = NameAndType #83:#84 // getDelta:()J #69 = Class #85 // java/lang/System #70 = NameAndType #86:#84 // currentTimeMillis:()J #71 = NameAndType #51:#52 // getMachineRelativeTime:(Ljava/lang/String;J)J #72 = NameAndType #46:#47 // hasMachine:(Ljava/lang/String;)Z #73 = NameAndType #48:#49 // getDeltaTime:(Ljava/lang/String;)J #74 = Utf8 com/bes/webgate/common/clock/RelativeTimeManager #75 = Utf8 java/lang/Object #76 = Utf8 getMachineId #77 = Utf8 ()Ljava/lang/String; #78 = Utf8 put #79 = Utf8 (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; #80 = Utf8 putIfAbsent #81 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object; #82 = Utf8 get #83 = Utf8 getDelta #84 = Utf8 ()J #85 = Utf8 java/lang/System #86 = Utf8 currentTimeMillis { private final java.util.concurrent.ConcurrentHashMap<java.lang.String, com.bes.webgate.common.clock.RelativeTime> cache; flags: ACC_PRIVATE, ACC_FINAL Signature: #24 // Ljava/util/concurrent/ConcurrentHashMap<Ljava/lang/String;Lcom/bes/webgate/common/clock/RelativeTime;>; public com.bes.webgate.common.clock.RelativeTimeManager(); flags: ACC_PUBLIC LineNumberTable: line 22: 0 line 20: 4 line 24: 15 LocalVariableTable: Start Length Slot Name Signature 0 16 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; Code: stack=3, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: new #2 // class java/util/concurrent/ConcurrentHashMap 8: dup 9: invokespecial #3 // Method java/util/concurrent/ConcurrentHashMap."<init>":()V 12: putfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap; 15: return LineNumberTable: line 22: 0 line 20: 4 line 24: 15 LocalVariableTable: Start Length Slot Name Signature 0 16 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; public void add(java.lang.String, long); flags: ACC_PUBLIC LineNumberTable: line 27: 0 line 28: 4 line 29: 15 line 31: 21 LocalVariableTable: Start Length Slot Name Signature 15 6 4 t Lcom/bes/webgate/common/clock/RelativeTime; 0 22 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 22 1 machineId Ljava/lang/String; 0 22 2 machineTime J Code: stack=5, locals=5, args_size=3 0: aload_1 1: ifnull 21 4: new #5 // class com/bes/webgate/common/clock/RelativeTime 7: dup 8: aload_1 9: lload_2 10: invokespecial #6 // Method com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V 13: astore 4 15: aload_0 16: aload 4 18: invokevirtual #7 // Method add:(Lcom/bes/webgate/common/clock/RelativeTime;)V 21: return LineNumberTable: line 27: 0 line 28: 4 line 29: 15 line 31: 21 LocalVariableTable: Start Length Slot Name Signature 15 6 4 t Lcom/bes/webgate/common/clock/RelativeTime; 0 22 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 22 1 machineId Ljava/lang/String; 0 22 2 machineTime J StackMapTable: number_of_entries = 1 frame_type = 21 /* same */ public void add(com.bes.webgate.common.clock.RelativeTime); flags: ACC_PUBLIC LineNumberTable: line 34: 0 line 35: 4 line 37: 17 LocalVariableTable: Start Length Slot Name Signature 0 18 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 18 1 time Lcom/bes/webgate/common/clock/RelativeTime; Code: stack=3, locals=2, args_size=2 0: aload_1 1: ifnull 17 4: aload_0 5: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap; 8: aload_1 9: invokevirtual #8 // Method com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String; 12: aload_1 13: invokevirtual #9 // Method java/util/concurrent/ConcurrentHashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 16: pop 17: return LineNumberTable: line 34: 0 line 35: 4 line 37: 17 LocalVariableTable: Start Length Slot Name Signature 0 18 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 18 1 time Lcom/bes/webgate/common/clock/RelativeTime; StackMapTable: number_of_entries = 1 frame_type = 17 /* same */ public void addIfAbsent(java.lang.String, long); flags: ACC_PUBLIC LineNumberTable: line 40: 0 line 41: 10 line 42: 21 line 44: 27 LocalVariableTable: Start Length Slot Name Signature 21 6 4 t Lcom/bes/webgate/common/clock/RelativeTime; 0 28 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 28 1 machineId Ljava/lang/String; 0 28 2 machineTime J Code: stack=5, locals=5, args_size=3 0: aload_1 1: ifnull 27 4: lload_2 5: lconst_0 6: lcmp 7: ifle 27 10: new #5 // class com/bes/webgate/common/clock/RelativeTime 13: dup 14: aload_1 15: lload_2 16: invokespecial #6 // Method com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V 19: astore 4 21: aload_0 22: aload 4 24: invokevirtual #10 // Method addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V 27: return LineNumberTable: line 40: 0 line 41: 10 line 42: 21 line 44: 27 LocalVariableTable: Start Length Slot Name Signature 21 6 4 t Lcom/bes/webgate/common/clock/RelativeTime; 0 28 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 28 1 machineId Ljava/lang/String; 0 28 2 machineTime J StackMapTable: number_of_entries = 1 frame_type = 27 /* same */ public void addIfAbsent(com.bes.webgate.common.clock.RelativeTime); flags: ACC_PUBLIC LineNumberTable: line 47: 0 line 48: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 14 1 time Lcom/bes/webgate/common/clock/RelativeTime; Code: stack=3, locals=2, args_size=2 0: aload_0 1: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap; 4: aload_1 5: invokevirtual #8 // Method com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String; 8: aload_1 9: invokevirtual #11 // Method java/util/concurrent/ConcurrentHashMap.putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 12: pop 13: return LineNumberTable: line 47: 0 line 48: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 14 1 time Lcom/bes/webgate/common/clock/RelativeTime; public void remove(java.lang.String); flags: ACC_PUBLIC LineNumberTable: line 51: 0 line 52: 4 line 54: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 14 1 machineId Ljava/lang/String; Code: stack=2, locals=2, args_size=2 0: aload_1 1: ifnull 13 4: aload_0 5: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap; 8: aload_1 9: invokevirtual #12 // Method java/util/concurrent/ConcurrentHashMap.remove:(Ljava/lang/Object;)Ljava/lang/Object; 12: pop 13: return LineNumberTable: line 51: 0 line 52: 4 line 54: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 14 1 machineId Ljava/lang/String; StackMapTable: number_of_entries = 1 frame_type = 13 /* same */ public boolean hasMachine(java.lang.String); flags: ACC_PUBLIC LineNumberTable: line 57: 0 line 58: 4 line 60: 6 LocalVariableTable: Start Length Slot Name Signature 0 23 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 23 1 machineId Ljava/lang/String; Code: stack=2, locals=2, args_size=2 0: aload_1 1: ifnonnull 6 4: iconst_0 5: ireturn 6: aload_0 7: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap; 10: aload_1 11: invokevirtual #13 // Method java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object; 14: ifnull 21 17: iconst_1 18: goto 22 21: iconst_0 22: ireturn LineNumberTable: line 57: 0 line 58: 4 line 60: 6 LocalVariableTable: Start Length Slot Name Signature 0 23 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 23 1 machineId Ljava/lang/String; StackMapTable: number_of_entries = 3 frame_type = 6 /* same */ frame_type = 14 /* same */ frame_type = 64 /* same_locals_1_stack_item */ stack = [ int ] public long getDeltaTime(java.lang.String); flags: ACC_PUBLIC LineNumberTable: line 64: 0 LocalVariableTable: Start Length Slot Name Signature 0 15 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 15 1 machineId Ljava/lang/String; Code: stack=2, locals=2, args_size=2 0: aload_0 1: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap; 4: aload_1 5: invokevirtual #13 // Method java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object; 8: checkcast #5 // class com/bes/webgate/common/clock/RelativeTime 11: invokevirtual #14 // Method com/bes/webgate/common/clock/RelativeTime.getDelta:()J 14: lreturn LineNumberTable: line 64: 0 LocalVariableTable: Start Length Slot Name Signature 0 15 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 15 1 machineId Ljava/lang/String; public long getMachineCurrentTime(java.lang.String); flags: ACC_PUBLIC LineNumberTable: line 68: 0 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 9 1 machineId Ljava/lang/String; Code: stack=4, locals=2, args_size=2 0: aload_0 1: aload_1 2: invokestatic #15 // Method java/lang/System.currentTimeMillis:()J 5: invokevirtual #16 // Method getMachineRelativeTime:(Ljava/lang/String;J)J 8: lreturn LineNumberTable: line 68: 0 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 9 1 machineId Ljava/lang/String; public long getMachineRelativeTime(java.lang.String, long); flags: ACC_PUBLIC LineNumberTable: line 72: 0 line 73: 8 line 74: 15 line 76: 20 LocalVariableTable: Start Length Slot Name Signature 15 5 4 delta J 0 22 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 22 1 machineId Ljava/lang/String; 0 22 2 time J Code: stack=4, locals=6, args_size=3 0: aload_0 1: aload_1 2: invokevirtual #17 // Method hasMachine:(Ljava/lang/String;)Z 5: ifeq 20 8: aload_0 9: aload_1 10: invokevirtual #18 // Method getDeltaTime:(Ljava/lang/String;)J 13: lstore 4 15: lload_2 16: lload 4 18: lsub 19: lreturn 20: lload_2 21: lreturn LineNumberTable: line 72: 0 line 73: 8 line 74: 15 line 76: 20 LocalVariableTable: Start Length Slot Name Signature 15 5 4 delta J 0 22 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; 0 22 1 machineId Ljava/lang/String; 0 22 2 time J StackMapTable: number_of_entries = 1 frame_type = 20 /* same */ }
从上面的class文件中,咱们就能够看出个大概结构:
从这两个文件的结构中,咱们能够轻松的看出一个class文件的结构:
须要注意的是,class文件中,是不会保留代码注释的。若是以非debug模式编译的话,连行号都不会有的。开发过程当中的class,都是有行号的,否则都没办法调试了。
从上面demo的常量池(Constant pool),能够看到包含了一个类的类型,方法描述,字段描述等。
同时也能够看出类名,方法名,字段名就是和源码同样的,可是字段的类型,方法的类型,和真是的java类型仍是有区别的。例如machineId的java类型java.lang.String,而class文件表示的则是 Ljava/lang/String; long表示为J
看来JVM中是有一套本身的表示方式的:
jvm type signature:
于此同时,我编写了一个java类向jvm type signature转换的工具:
Jvm中也有本身的一套method signature:
(paramTypeSignatures)returnTypeSignature
例如:
有了上面的类型签名的转换工具,想必实现方法前面的转换也就不成问题的了。
Java类型,方法在jvm都有一套本身的表示方式,Java5中引入的泛型,也天然有一套表示方式的,感兴趣的话,能够本身了解一下。
下面是一些简单的例子:
了解了class文件结构,类型,方法的表示后,下面就进入重头戏了——查看方法。
从上面的字节码,也能看出一个方法会有一堆的指令组成。每个方法,大概有这些描述区域:
1) modifier(flags:)
2) LineNumberTable (debug模式编译的class文件才会有,反编译工具反编译处理的代码行号之因此对应,你之因此能够调试代码,就是依赖于此)
3) LocalVariableTable (局部变量表,包含三部份内容: this, 方法的全部参数,方法体中声明的全部局部变量)
4) Code (指令序列,运行是就是按照该序列执行的)
5)StackMapTable(stack map frames table,用于jvm在加载类时,verify阶段对code中指令序列里,在全部的跳转指令处,进行execute method stack frame状态校验。目前可能对这句话不理解,不要急,看了后面的内容,就理解了)
若是你稍有Java开发经验,应该都会调试过代码,或者用jstack打过运行时调用栈,或者是看过exception stack。也就是,在运行时采用stack结构各个方法的调串成一条调用链的。在jvm内部,将运行时stack中的每个元素(方法调用)看做是一个execute frame。
每个execute frame由两部分组成:一个local variables table,一个operand stack。
Local variables table用于放局部变量,this等。
Operand stack 是执行指令时涉及的操做数存放的地方。
Java运行时的最小单位就是指令的执行。一条完整的指令包括两部分,一个是操做码(opcode),一个是操做数(operand)。
例如:IADD a,b ,这条指令是执行a + b, IADD是 opcode, a,b 是operand。
也就是说operand能够理解为opcode的参数。
指令执行时,一般是对三个地方的数据 进行操做1)local variables table, 2) operand stack, 3) constant pool 。
Jvm 提供了不少指令,这些指令大概能够分为两类:
1) 从local variables table 或者 constants pool 将值load到 operand stack,或者反过来将 operand stack 中的值 store 给local variables table。
2) 基于stack 进行操做,例如 IADD, 就从 stack 顶取2个值进行 加法运算后,将结果push到stack。
到此,相信能够大概猜想出运行过程 :执行一个方法时:
1) 构建 execute frame (初始化 local variables table, operand stack)
2) 将execute frame 放到 thread stack。
在构建local variables table时,第一个(也就是index 为0的)是this, 后面紧接的是方法的参数列表。
在执行方法内的指令序列时,碰见 load类指令时,就load数据到operand stack,碰见运算类指令时,就从 operand stack 中取值运行,碰见 store类指令时,就从stack顶取值放到local variables table中。
从Java 6起,引入了使用stack map frames进行字节码校验机制。那么stack map frames究竟是怎样一回事呢?
假设你的类,被人篡改了,加入了一些不可描述的指令。经过jvm 的stack map frames检验,是能够帮你查出来问题的。
上面已经说明了operand stack,也了解了指令执行过程,能够说大多数指令,都是要与operand stack打交道的。这个检验就是基于operand stack在执行指令先后的状态来的。
例如:
上面 就是一个stack map。也就是说记录了指令执行先后,operand stack 与 指令的映射关系的表,就是 stack map frames。
一个方法能够很简单,也能够很复杂。对于一个复杂的方法,指令会很是多,那么它的stack map frames 会很是长。若是类加载过程当中,要校验这么长的stack map,那性能可想而知。
因此JVM设计者呢,采起了一个折中的方案。只在stack map frames 里只保留跳转指令的状态。至于跳转指令,例如:if,else,try,catch等。
目前经常使用的字节码操做的工具备:javaassist,asm,bcel
基于asm的库有bytebuddy,cglib
在上面说了,指令主要针对local variables table, operand stack, constants进行操做。若是详细对指令进行归类的话,大概能够归类以下:
1) Local variables
2) stack
3) Constants
4) Arithmetic and logic
5) Object,field,method
6) Array
7) Jump
8) Return