2016-08-25 68 views
1

我們目前使用premain在所有的類加載之前進行轉換。 但是我們想要控制轉換,這意味着我們可以刪除/重新添加我們在方法中插入的代碼。加載後我們可以重新轉換類嗎?

所以我們發現了轉換,但我不是很理解它。

  1. 我們可以重新轉換加載類嗎?
  2. 如果可以完成,重新轉換類的實例是否會運行重新轉換後的代碼?
  3. 如果無法完成,是否有任何技術可以在運行時更改某些指定方法的代碼。

修訂

例如,我們有A級類A有兩個方法foo()和bar():

void foo() { 
    while(true) { 
     bar(); 
    } 
} 
void bar() { 
    System.out.println("a"); 
} 

我們稱之爲Instrument.retransformClasses(一類)。和更改欄()來:

void bar() { 
    System.out.println("b"); 
} 

如果有一個線程調用已經FOO(),我們可以有輸出:

... 
a 
a 
a 
b 
b 
b 
... 

如果沒有,有沒有什麼辦法來實現呢?

+0

「變形」是什麼意思? – byxor

+1

[在運行時更新Java代碼]的可能副本(http://stackoverflow.com/questions/3079280/update-java-code-during-runtime) – Blobonat

+0

我們當前實現了一個ClassFileTransformer來在每個類的方法中插入一些代碼有一個特殊的註釋。根據我的理解,轉換正在改變類的字節碼(至少,它看起來像改變字節碼,根據ClassFileTransformer#transform()的javadoc)。 –

回答

1

因此,您已經有了一個ClassFileTransformer來轉換類的字節碼,然後將其加載並安裝到JVM中。現在你想要在JVM生命週期中再次進行重新轉換,不是嗎?那麼,可以通過儀器,通過Instrumentation.retransformClasses方法來完成重新轉換。但首先,您必須確保通過調用Instrumentation.isRetransformClassesSupported來支持重新轉換。

這種轉換何時會起作用?根據javadocs:

如果重新構建的方法具有活動堆棧幀,那些活動幀將繼續運行原始方法的字節碼。重新編譯的方法將用於新的調用。

這意味着,在您的示例中,foo()重複調用bar()。如果在此期間bar被重新轉換,則轉換的代碼將在下一次迭代中生效,該代碼調用bar

我會添加一些更復雜的例子:

void foo() { 
    while(true) { 
     bar(); 
    } 
} 

void bar() { 
    myRetransform(); 
    System.out.println("a"); 
} 

void myRetransform() { 
    // This is where a retransformation of class A, method bar, is triggered. 
} 

當重轉換被觸發,當前棧幀是:

  • myRetransform

有一個bar的活動調用堆棧幀,所以當myRetransform返回時它仍然會在system.out中打印一個「a」。

然後,bar將返回和這樣離開當前棧幀:

而且現在是當最後一個觸發的轉型將生效。即:在下一次調用bar時。

相關問題