繁体   English   中英

为什么 Spring Around 建议可以吞下或停止目标方法抛出的异常的传播?

[英]Why a Spring Around advice can swallow, or halt the propagation of, an exception thown by the target method?

我正在为 Spring Core 认证而学习,根据我的学习材料,我对这个问题有以下疑问:

下列关于通知类型和异常处理的说法不正确的是?

  • 如果Before通知抛出异常,则不会调用目标方法。

  • 一个Around通知可以吞下或停止由目标方法抛出的异常的传播。

  • AfterReturning通知类型可以吞下或停止目标方法抛出的异常的传播。

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

所以它问我什么陈述是不正确的,所以这意味着前两个陈述是正确的。

我试图通过一些具体的例子来分析前 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…”);
   }
}

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

我认为这很清楚

2)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;
}

阅读官方文档我发现:

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

所以在我看来, Around 建议用于在关节点执行之前和之后切断方法执行。 我们可以使用它来控制建议的方法是否会执行。 我们还可以检查返回值并更改它。 这是最有力的建议,需要正确应用。

所以在上例中我认为这是执行两次时间:第一个时所执行的getName()方法之前以及在执行getName()方法之后的第二个。

但究竟是什么

value = proceedingJoinPoint.proceed();

我认为它是关节点前后执行的分割点,在这种情况下我认为proceed()方法说必须执行getName()方法并将其结果放入字段。 是对的还是我错过了什么?

所以回到最初的声明,我可以说

一个Around通知可以吞下或停止由目标方法抛出的异常的传播。

为什么我可以说这是真的? 具体是什么意思?

因此,在前面的示例中,我认为它执行了两次:执行 getName() 方法之前的第一次和执行 getName() 方法之后的第二次。

如果我理解你在这里的想法,那你就错了。 建议只调用一次,其中的代码负责调用实际的建议方法getName() 这就是proceedingJoinPoint.proceed()所做的。

一种典型场景 - 您拦截方法调用,执行一些检查,调用该方法(或不调用,可能取决于检查结果),然后返回结果。 在您发布的示例中, proceed()try - catch块包围,这意味着您可以捕获getName()抛出的异常并对其执行任何您想做的操作。 这解释了为什么您问题中的第二句话是正确的。

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

弹簧文档

环绕通知使用@Around 注释声明。 建议方法的第一个参数必须是 ProceedingJoinPoint 类型。 在通知正文中,对 ProceedingJoinPoint 调用proceed() 会导致执行底层方法。 也可以调用继续方法,传入 Object[] - 数组中的值将用作方法执行时的参数。

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

一个Around 通知可以吞下或停止由目标方法抛出的异常的传播。

这是通过执行以下操作来发生的:

try {
   proceedingJoinPoint.proceed();
} catch (Throwable e) {
    // ignore or handle
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM