5

我在我们的 Java 项目中使用的一个通用实用程序中有一个设计问题,我想确保特定方法 A 的所有调用者都被另一个方法 B 包装。我今天编写的这段代码的一般形式是:

x.B(new Runnable() {
    y.A();
});

B正在执行的runnable可以有任意代码,并且可能多次调用A,所以我无法通过将A的调用直接添加到B中来摆脱这段代码中的runnable。另外,A是第三方代码,所以我们不能修改它。runnable 可能会通过另一个对 A 的嵌套调用再次调用 B,但是今天这种情况从未发生过,所以我现在可以忽略这种情况。

我看到几个选项:

  1. 声明A() throws BlahException并使其 B 成为该异常的唯一捕获者。这很难看,因为不应该真正抛出任何异常,但这很好,因为编译器会为我确保调用层次结构。
  2. 编写某种静态分析工具来确保我的这条规则。我还没有对这个案例进行太多调查,因为这听起来比其他任何事情都需要更多的工作(但也许有一个预先存在的工具可以做到这一点?)。
  3. 向“A 的开头”添加一个断言(实际上,此代码必须存在于 Runnble 的自定义版本中,因为我无法直接修改 A)我们正在对 B 的调用中运行。这可以使用一些额外的线程/对象本地状态或遍历调用堆栈本身,这两者都很丑陋。

还有其他我没有考虑过的选择吗?

4

1 回答 1

2

您是否考虑过使用AspectJ或其他一些面向方面的编程 (AOP) 工具?然后你可以拦截对方法的每次调用A,检查B堆栈跟踪中的方法。如果它不存在,您可以抛出异常以阻止执行A,或者将错误写入日志,或者做任何您喜欢的事情。像这样的东西:

@Aspect
public class CheckInsideMethodBAspect {

    @Around("execution(* com.example.AClass.A(..))")
    public void checkNestedMethod(ProceedingJoinPoint joinPoint) {

        // checking for method B in the call stack
        boolean isInsideB = false;
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        for (StackTraceElement element: stackTraceElements) {
            if (element.getClassName().equals("ClassB") && element.getMethodName().equals("B")) {
                isInsideB = true;
                break;
            }
        }

        // if not inside B, throwing exception
        if (!isInsideB) {
            throw new NotInsideBException();
        }

        // if inside B, then proceeding with method A execution
        joinPoint.proceed();
    }

}
于 2015-05-26T19:06:53.337 回答