老实说,最简单的解决方案是通过从不从类中调用同一类的另一个公共/注释方法来简单地避免该问题:
public class MyClass {
  @MyAnnotation
  public void foo() {
     doBar();
  }
  @MyAnnotation
  public void bar() {
     doBar();
  }
  private void doBar() {
     //doesn't go through interceptor
  }
}
如果由于某种原因这不是一种选择,那么您可能会考虑这种方法。更具表现力的 AOP 库(如 AspectJ)为您定义切入点提供了更高级别的灵活性。
在 Guice 中,切入点只是一个带有注释的方法,该注释属于由 Guice 实例化的实例。所以这个逻辑必须转移到拦截器本身。
这样做的一种方法可能是使用 aThreadLocal来跟踪进入拦截器的条目。扩展这样的东西可能是一个开始:
public abstract class NonReentrantMethodInterceptor implements MethodInterceptor {
    private final ThreadLocal<Deque<Object>> callStack = new ThreadLocal<>();
    @Override
    public final Object invoke(MethodInvocation invocation) throws Throwable {
        Deque<Object> callStack = this.callStack.get();
        if (callStack == null) {
            callStack = new LinkedList<>();
            this.callStack.set(callStack);
        }
        try {
            return invokeIfNotReentrant(callStack, invocation);
        } finally {
            if (callStack.isEmpty()) {
                this.callStack.remove();
            }
        }
    }
    private final Object invokeIfNotReentrant(Deque<Object> callStack, MethodInvocation invocation) throws Throwable {
        Object target = invocation.getThis();
        if (callStack.isEmpty() || callStack.peek() != target) {
            //not being called on the same object as the last call
            callStack.push(target);
            try {
                return doInvoke(invocation);
            } finally {
                callStack.pop();
            }
        } else {
            return invocation.proceed();
        }
    }
    protected abstract Object doInvoke(MethodInvocation invocation) throws Throwable;
}
这使用线程本地堆栈来跟踪对拦截器的调用堆栈。当对该拦截器的最后一次调用针对同一个对象时,它会调用proceed()并绕过该拦截器。当这是第一次调用拦截器时,或者如果最后一次调用不是针对同一个对象,它会应用拦截器。
然后,当拦截器处于活动状态时,您想要应用的实际逻辑将进入doInvoke().
示例用法:
public class NonReentrantTester {
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new Module());
        MyClass instance = injector.getInstance(MyClass.class);
        instance.foo();
    }
    static class Module extends AbstractModule {
        @Override
        protected void configure() {
            bindInterceptor(Matchers.any(), Matchers.annotatedWith(PrintsFirstInvocation.class), 
                    new PrintsFirstInvocationInterceptor());
        }
    }
    public static class MyClass {
        @PrintsFirstInvocation
        void foo() {
            bar();
        }
        @PrintsFirstInvocation
        void bar() {
        }
    }
    public static class PrintsFirstInvocationInterceptor extends NonReentrantMethodInterceptor {
        @Override
        protected Object doInvoke(MethodInvocation invocation) throws Throwable {
            System.out.println(invocation.getMethod());
            return invocation.proceed();
        }
    }
    @BindingAnnotation
    @Target({FIELD, PARAMETER, METHOD})
    @Retention(RUNTIME)
    public @interface PrintsFirstInvocation {
    }
}