如何避免使用byte buddy进行递归调用 - java.lang.StackOverflowError

时间:2017-04-21 10:56:50

标签: servlet-filters byte-buddy

我有一个建议,在建议中调用类似的方法。我们如何确保一次只调用一次建议。现在,因为我在通知中调用的方法与正在检测的方法相同,所以它进入递归调用并导致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));
    }

1 个答案:

答案 0 :(得分:0)

Byte Buddy是一个代码生成框架,不是面向方面的。想一想将代码复制粘贴到目标位置;如果您将检测硬编码到目标方法中,那么您所看到的堆栈溢出错误将是相同的。

这可以通过添加标志来避免,例如,您可以在进行递归调用之前定义一个设置为true的ThreadLocal<Boolean>,例如:

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

这样,您就可以跟踪递归调用。但是你确实需要管理你的州。一种选择是使用Instrumentation接口将属性的holder类注入bootstrap类加载器。

或者,您可以检查堆栈是否有重复呼叫。这不如显式状态管理那么有效,但从Java 9开始,您可以使用更便宜的堆栈walker API并使其变得平易近人。