2016-11-29 92 views
2

我嘗試使用下面的代碼重新定義一個類Bar 2種方法:重新定義一個方法覆蓋以前的重新定義

private <T> Class<? extends T> replaceMethodInClass(final Class<T> subclass, 
    final ClassFileLocator classFileLocator, final String methodName) { 
    final Builder<? extends T> classBuilder = 
     this.bytebuddy.redefine(subclass, classFileLocator); 
    return classBuilder 
     .method(ElementMatchers.named(methodName)) 
     .intercept(MethodDelegation.to(CustomInterceptor.class)) 
     .make() 
     .load(ByteBuddyReplaceMethodInClassTest.class.getClassLoader(), 
      ClassReloadingStrategy.fromInstalledAgent()) 
     .getLoaded(); 
} 

其中CustomInterceptor類如下:

static class CustomInterceptor { 
    public static String intercept() { 
    return "Hello!"; 
    } 
} 

在我測試,我做了以下重新定義Bar#sayHello()Bar#sayHelloAgain()方法:

@Test 
public void shouldReplaceTwoMethodsFromClass_instanciateAfterChanges() 
    throws InstantiationException, IllegalAccessException, Exception { 
    // given 
    replaceMethodInClass(Bar.class, ClassFileLocator.ForClassLoader.of(Bar.class.getClassLoader()), 
     "sayHello"); 
    replaceMethodInClass(Bar.class, ClassFileLocator.ForClassLoader.of(Bar.class.getClassLoader()), 
     "sayHelloAgain"); 
    // when 
    final Bar instance = Bar.class.newInstance(); 
    final String hello = instance.sayHello(); 
    final String helloAgain = instance.sayHelloAgain(); 
    // then 
    assertThat(hello).isEqualTo("Hello!"); 
    assertThat(helloAgain).isEqualTo("Hello!"); 
} 

請注意,我明確地想要逐個替換方法。 因爲hello變量是null的測試失敗(這是通過在Bar類的Bar#sayHello()方法返回的值),但helloAgain變量被設置爲Hello!,如所預期(使用了CustomInterceptor類)。所以看起來第一個方法重定義在第二個方法時被刪除了。

你有什麼想法發生了什麼,以及如何保持2方法重新定義,而不是丟失第一個?

回答

1

這一切都取決於您正在使用的ClassFileLocator。您正在使用查詢類加載器的類文件定位器。類加載器始終返回最初可從類文件中獲得的類文件,並且不知道任何轉換。

如果要保留第一次轉換的更改,則需要在類文件定位器中構建某種形式的內存以返回已更改的類文件。您可以讀取從dynamicType.getBytes()轉換生成的字節。

您還可以查看使用Java API的儀器現場的類文件通過ClassFileLocator.AgentBased這確實需要但附加一個Java代理。

+0

感謝您的迴應,拉斐爾!所以,爲了保持以前的變化,我可以使用基於目錄(即ClassFileLocator:'新ClassFileLocator.ForFolder(this.classDir)',在這我每一個方法被重新定義時間節省類的字節碼? –

+0

是的,這可能是最可靠的方法。 –

+0

是的,的確,我是能夠做到這樣的,它再完美的作品。感謝您的支持,拉斐爾! –