如何避免使用 byte buddy 进行递归调用 - java.lang.StackOverflowError
how to avoid recursive calls with byte buddy - java.lang.StackOverflowError
我有一个建议在建议中调用类似的方法。我们如何确保通知被调用一次且仅调用一次。现在,由于我在建议中调用的方法与正在检测的方法相同,它进入递归调用并导致 java.lang.WhosebugError.
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));
}
Byte Buddy 是一个代码生成框架,不是面向方面的。想想代码被复制粘贴到目标位置;如果您将检测硬编码到目标方法中,您看到的堆栈溢出错误将是相同的。
这可以通过添加一个标志来避免,例如,您可以定义一个 ThreadLocal<Boolean>
并在进行递归调用之前将其设置为 true,例如:
if (!threadLocal.get()) {
threadLocal.set(true);
try {
// your code here.
} finally {
threadLocal.set(false);
}
}
这样,您可以跟踪递归调用。但是,您确实需要在某个地方管理您的状态。一种选择是使用 Instrumentation
接口将 属性 的 holder class 注入 bootstrap class 加载程序。
或者,您可以检查递归调用的堆栈。这不如显式状态管理有效,但从 Java 9 开始,您可以使用堆栈 walker API,它更便宜并且更容易实现。
我有一个建议在建议中调用类似的方法。我们如何确保通知被调用一次且仅调用一次。现在,由于我在建议中调用的方法与正在检测的方法相同,它进入递归调用并导致 java.lang.WhosebugError.
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));
}
Byte Buddy 是一个代码生成框架,不是面向方面的。想想代码被复制粘贴到目标位置;如果您将检测硬编码到目标方法中,您看到的堆栈溢出错误将是相同的。
这可以通过添加一个标志来避免,例如,您可以定义一个 ThreadLocal<Boolean>
并在进行递归调用之前将其设置为 true,例如:
if (!threadLocal.get()) {
threadLocal.set(true);
try {
// your code here.
} finally {
threadLocal.set(false);
}
}
这样,您可以跟踪递归调用。但是,您确实需要在某个地方管理您的状态。一种选择是使用 Instrumentation
接口将 属性 的 holder class 注入 bootstrap class 加载程序。
或者,您可以检查递归调用的堆栈。这不如显式状态管理有效,但从 Java 9 开始,您可以使用堆栈 walker API,它更便宜并且更容易实现。