AOP 示例

既然您已经了解了所有构成部分的工作原理,我们可以将它们组合起来做一些有用的事情。

业务服务的执行有时会因为并发问题(例如,死锁失败者)而失败。如果操作被重试,它很可能在下一次尝试中成功。对于在这种条件下适合重试的业务服务(不需要返回给用户进行冲突解决的幂等操作),我们希望透明地重试操作,以避免客户端看到 PessimisticLockingFailureException。这是一个明显贯穿服务层中多个服务的需求,因此,非常适合通过切面实现。

因为我们想要重试操作,所以我们需要使用环绕通知,以便我们可以多次调用 proceed。以下清单显示了基本的切面实现:

@Around("com.xyz.CommonPointcuts.businessService()") 引用了 共享命名切点定义 中定义的 businessService 命名切点。

请注意,切面实现了 Ordered 接口,以便我们可以将切面的优先级设置高于事务通知(我们希望每次重试都有一个新的事务)。maxRetriesorder 属性都由 Spring 配置。主要操作发生在 doConcurrentOperation 环绕通知中。请注意,目前,我们将重试逻辑应用于每个 businessService。我们尝试继续执行,如果因 PessimisticLockingFailureException 失败,我们会再次尝试,除非我们已用尽所有重试尝试。

相应的 Spring 配置如下:

为了优化切面,使其仅重试幂等操作,我们可以定义以下 Idempotent 注解:

然后,我们可以使用该注解来注解服务操作的实现。对切面进行更改以仅重试幂等操作涉及优化切点表达式,以便只有 @Idempotent 操作匹配,如下所示: