Как избежать рекурсивных вызовов с помощью байта приятель - java.lang.StackruError

У меня есть совет, который вызывает аналогичный метод в совете. Как сделать так, чтобы совет вызывался один раз и только один раз? Прямо сейчас, так как метод, который я вызываю в рамках совета, тот же, что и инструментальный, он переходит в рекурсивный вызов и приводит к java.lang.StackruError.

 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 ответ

Решение

Byte Buddy - это структура генерации кода, которая не является аспектно-ориентированной. Подумайте о коде, вставляемом в целевое местоположение; ошибка переполнения стека, которую вы видите, будет такой же, если вы жестко закодируете инструментарий в свой целевой метод.

Этого можно избежать, добавив флаг, например, вы можете определить ThreadLocal<Boolean> что вы установили в true перед выполнением рекурсивного вызова, например:

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

Таким образом, вы можете отслеживать рекурсивный вызов. Вам, однако, нужно управлять своим состоянием. Один из вариантов - вставить класс держателя для вашего свойства в загрузчик классов начальной загрузки, используя Instrumentation интерфейс.

Кроме того, вы можете проверить стек для повторного вызова. Это не так эффективно, как явное управление состоянием, но начиная с Java 9, вы можете использовать API обхода стека, который намного дешевле и делает его доступным.

Другие вопросы по тегам