2017-04-21 60 views
1

我有一個建議,在通知中調用類似的方法。我們如何確保建議一次又一次被調用。現在,我在advice中調用的方法與正在調用的方法相同,它會進入遞歸調用並導致java.lang.StackOverflowError。如何避免與字節好友遞歸調用 - java.lang.StackOverflowError

transform(
       new AgentBuilder.Transformer.ForAdvice() 
.include(JettyHandlerAdvice.class.getClassLoader()) 
.advice(named("addFilterWithMapping").and(ElementMatchers.takesArgument(0,named("org.eclipse.jetty.servlet.FilterHolder"))),JettyHandlerAdvice.class.getName()) 
         ) 

忠告

@Advice.OnMethodEnter 
    private static void before(@Advice.AllArguments Object[] args, @Advice.Origin("#m") String methodName, @Advice.This Object thiz) {   
     FilterHolder filterHolder = ((org.eclipse.jetty.servlet.ServletHandler)thiz).addFilterWithMapping(XYZFilter.class, "/*", EnumSet.of(javax.servlet.DispatcherType.REQUEST)); 
    } 

回答

0

字節Buddy是一個代碼生成框架,而不是面向方面。考慮將代碼複製粘貼到目標位置;如果您將儀器硬編碼到目標方法中,則您正在使用的堆棧溢出錯誤將會相同。

這可以通過添加一個標誌來避免,例如,你可以定義一個ThreadLocal<Boolean>,你做遞歸調用之前設置爲true,例如:

if (!threadLocal.get()) { 
    threadLocal.set(true); 
    try { 
    // your code here. 
    } finally { 
    threadLocal.set(false); 
    } 
} 

這樣,您就可以跟蹤遞歸調用。但是,你確實需要管理你的國家。一種選擇是使用Instrumentation接口爲您的資產注入持有人類到引導類加載器。

或者,您可以檢查堆棧以進行重複呼叫。這並不像明確的狀態管理那樣高效,而是從Java 9開始,您可以使用更便宜且易於使用的棧式API。