多个切面、多种通知同时作用在一个方法上,谁先谁后?@After 和 @AfterReturning 谁在前?@Order 写在哪里才有用?@Around 能做什么?这篇在 Spring Framework 7.0.9 上用带编号的时间线逐项验证。
--- 正常返回 ok()(A 的 @Order(1),B 的 @Order(2)) 1. A.around 前 2. A.before 3. B.around 前 4. B.before 5. ▶ 目标方法 ok() 6. B.afterReturning 7. B.after 8. B.around 后(finally) 9. A.afterReturning 10. A.after(finally 型) 11. A.around 后(finally) --- 抛异常 fail() 1. A.around 前 2. A.before 3. B.around 前 4. B.before 5. ▶ 目标方法 fail() 抛异常 6. B.afterThrowing 7. B.after 8. B.around 后(finally) 9. A.afterThrowing 10. A.after(finally 型) 11. A.around 后(finally) 12. 调用者收到 IllegalStateException
顺序小的切面在外层;同一个切面内按 Around、Before、目标、AfterReturning 或 AfterThrowing、After 展开。
--- 正常返回 ok()(A 的 @Order(1),B 的 @Order(2);这次 @Bean 的定义顺序是 B 先 A 后) 1. A.around 前 2. A.before 3. B.around 前 4. B.before 5. ▶ 目标方法 ok() 6. B.afterReturning 7. B.after 8. B.around 后(finally) 9. A.afterReturning 10. A.after(finally 型) 11. A.around 后(finally) --- 抛异常 fail() 1. A.around 前 2. A.before 3. B.around 前
有 @Order 时 @Bean 的定义顺序不影响通知顺序。
--- 同一个切面里的多个通知,没有 @Order 1. Names.mmm(@Around)前 2. Names.aaa(后声明) 3. Names.zzz(先声明) 4. ▶ 目标方法 ok() 5. Names.yyy(@After) 6. Names.mmm(@Around)后
看起来按方法名排序,不是按声明顺序。
--- @Around 里修改参数后 proceed(Object[]) 1. Skip.around 看到参数 [原值],改成 [改过]后 proceed 2. ▶ 目标方法 arg(改过) 3. 返回值 = 改过 --- @Around 不调用 proceed() 1. Swallow.around 没有调用 proceed(),直接返回 "缓存值" 2. 返回值 = 缓存值
可以改参数、不调用 proceed() 直接返回。
--- 三个切面:Plain(没有顺序)、OrderedViaBean(@Bean 方法上 @Order(-5))、OrderedViaInterface(实现 Ordered,getOrder=0) 1. OrderedViaInterface(getOrder=0).before 2. PlainNoOrder.before 3. OrderedViaBean.before 4. ▶ 目标方法 ok()
类上的 @Order 与 Ordered 接口有效,@Bean 方法上的 @Order 对切面没有效果。