JVM 指令

       在java程序開發過程當中,沒有源碼是很常見的事,咱們能夠經過IDE(Eclipse須要配置jad.exe、IDEA)自動的將class文件反編譯爲java文件。或者咱們藉助於其餘工具(jd-gui, luyten)來直接的對整個jar包進行反編譯。反編譯工具是如何作到代碼反編譯的呢?若是是在生產環境下幫助用戶解決問題時,是沒有這些工具的,該怎麼辦呢?java

       在開發apm,jprofiler這樣的工具時,spring團隊在實現aop (例如interceptor),一般都會經過字節碼 技術對已有代碼進行改造,以達到對代碼進行監控,改造工做。那麼又是如何將字節碼指令嵌入的呢?web

       要想了解這些東西,不學習class文件如何看,不瞭解相關字節碼指令是很難解決上面的問題的。spring

一、Demo

       在瞭解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;
    }
}
View Code
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;
    }
}
View Code

 

先來解決上面提出的第一個問題,沒有反編譯工具的狀況下如何查看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
}
View Code

 

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 */

}
View Code

  

二、Class 文件說明

2.1 Class 文件結構

 

從上面的class文件中,咱們就能夠看出個大概結構:

 

 

從這兩個文件的結構中,咱們能夠輕鬆的看出一個class文件的結構:

 

須要注意的是,class文件中,是不會保留代碼註釋的。若是以非debug模式編譯的話,連行號都不會有的。開發過程當中的class,都是有行號的,否則都沒辦法調試了。

 

2.2 jvm type 、method signature

從上面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

例如: 

 

 

有了上面的類型簽名的轉換工具,想必實現方法前面的轉換也就不成問題的了。

 

2.3 泛型表示

 

Java類型,方法在jvm都有一套本身的表示方式,Java5中引入的泛型,也天然有一套表示方式的,感興趣的話,能夠本身瞭解一下。

 下面是一些簡單的例子:

 

 

 

三、方法說明

瞭解了class文件結構,類型,方法的表示後,下面就進入重頭戲了——查看方法。

 

3.1 方法結構

從上面的字節碼,也能看出一個方法會有一堆的指令組成。每個方法,大概有這些描述區域:

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狀態校驗。目前可能對這句話不理解,不要急,看了後面的內容,就理解了)

 

 

3.1.1 Thread Stack Model

若是你稍有Java開發經驗,應該都會調試過代碼,或者用jstack打過運行時調用棧,或者是看過exception stack。也就是,在運行時採用stack結構各個方法的調串成一條調用鏈的。在jvm內部,將運行時stack中的每個元素(方法調用)看做是一個execute frame。

每個execute frame由兩部分組成:一個local variables table,一個operand stack。

Local variables table用於放局部變量,this等。

Operand stack 是執行指令時涉及的操做數存放的地方。

 

  

3.1.2 指令

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中。

 

 

3.1.3 Stack Map Frames

 

從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

 

相關文章
相關標籤/搜索