2017-04-21 59 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。