为什么Spring Around建议可以吞噬或停止传播目标方法所引发的异常?

And*_*ili 4 java aop spring spring-mvc spring-aop

我正在攻读Spring Core认证,对于基于我的学习资料的这个问题,我有以下疑问:

有关建议类型和异常处理的以下哪些陈述不正确?

  • 如果Before建议抛出异常,则不会调用目标方法.

  • 一个围绕建议可吞咽,或停止的传播,由目标方法thown异常.

  • 一个AfterReturning通知类型可吞咽,或停止的传播,由目标方法thown异常.

现在我知道前一个问题的正确答案是最后一个(我有答案),但为什么呢?

所以它问我什么样的陈述不正确所以这意味着前2个陈述是真的.

我试图分析之前的3个案例做一些具体的例子,但我并不认为我的推理是正确的.

1)建议之前:

我可以这样:

@Aspect
public class PropertyChangeTracker {
    private Logger logger = Logger.getLogger(getClass());

    @Before(“execution(void check*(*))”)
    public void trackCheck() {
        logger.info(“Property about to check…”);
   }
}
Run Code Online (Sandbox Code Playgroud)

因此,每次执行checkSomething(oneArgument)方法时,都会执行已实现的建议(在.log文件中创建日志行).如果在执行此方法期间抛出异常,则不执行建议.

我认为这很清楚

2)AROUND ADVICE,我知道这是Around建议的序列图

在此输入图像描述

我有以下这种建议的例子:

@Around("execution(* com.journaldev.spring.model.Employee.getName())")
public Object employeeAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
    System.out.println("Before invoking getName() method");
    Object value = null;
    try {
        value = proceedingJoinPoint.proceed();
    } catch (Throwable e) {
        e.printStackTrace();
    }
    System.out.println("After invoking getName() method. Return value="+value);
    return value;
}
Run Code Online (Sandbox Code Playgroud)

阅读官方文档我发现:

围绕建议:围绕连接点的建议,例如方法调用.这是最有力的建议.around通知可以在方法调用之前和之后执行自定义行为.它还负责选择是继续加入点还是通过返回自己的返回值或抛出异常来快速建议的方法执行.

因此在我看来,在关节点执行之前和之后,使用了周围的建议来减少方法执行.我们可以用它来控制建议的方法是否会执行.我们还可以检查返回的值并进行更改.这是最强大的建议,需要正确应用.

所以在前面的例子中我认为它执行了两次:第一个执行getName()方法之前执行,第二个执行getName()方法执行.

但究竟是什么呢

value = proceedingJoinPoint.proceed();
Run Code Online (Sandbox Code Playgroud)

我认为它是联合点之前和之后的执行之间的分界点,在这种情况下我认为proceed()方法必须执行getName()方法,并将其结果放入价值领域.是对的还是我错过了什么?

所以回到原来的陈述,我可以这么说

一个围绕建议可吞咽,或停止的传播,由目标方法thown异常.

为什么我能说这是真的?什么是繁琐的意思?

Pre*_*ric 6

所以在前面的例子中我认为它执行了两次:第一个执行getName()方法之前执行,第二个执行getName()方法执行.

如果我理解你的想法,那你错了.该建议只被调用一次,其中的代码负责调用实际的建议方法getName().这是什么proceedingJoinPoint.proceed().

一个典型的场景 - 你拦截方法调用,执行一些检查,调用方法(或不,可能取决于检查的结果),并返回结果.在你发布的例子中,proceed()try - catchblock 包围,这意味着你可以捕获由getName()它抛出的异常,并随意做任何事情.这就解释了为什么你问题中的第二句是真的.


bee*_*jay 5

使用@Around就像编写自己的代码并调用方法一样,除了您使用之外proceedingJoinPoint.proceed().与普通方法调用一样,您可以选择不执行它(将其包装在条件中)或捕获它抛出的错误(将调用包装在try块中).

春季文档:

使用@Around注释声明around建议.advice方法的第一个参数必须是ProceedingJoinPoint类型.在通知的主体内,在ProceedingJoinPoint上调用proceed()会导致执行基础方法.proceed方法也可以被称为传入Object [] - 数组中的值将在进行时用作方法执行的参数.

因此,具体来说:value = proceedingJoinPoint.proceed();导致调用底层方法并将其返回值赋值给value.

Around建议可以吞噬或停止目标方法所引发的异常的传播.

这通过以下方式发生:

try {
   proceedingJoinPoint.proceed();
} catch (Throwable e) {
    // ignore or handle
}
Run Code Online (Sandbox Code Playgroud)