当前位置: 首页 > news >正文

Spring AOP核心:Advice类型与实战解析

🌟 总览:什么是 Spring AOP 的 Advice?

在 AOP 中:

  • Advice(通知/增强) 是“在某个连接点(方法调用)上要执行的代码”。
  • 比如:在方法执行前打印日志、在方法抛出异常后记录错误、在方法返回后统计调用次数等。

Spring AOP 支持多种类型的 Advice,并通过代理机制实现。我们来看你提供的内容是如何组织的:


6.2 Advice API in Spring

这一节讲的是:Spring AOP 是如何处理各种 Advice 的?


6.2.1 Advice 的生命周期(Lifecycles)

核心观点:

每个 Advice 都是一个 Spring Bean,可以是:

  1. Per-class(类级别共享):所有被代理的对象共用同一个 Advice 实例。
  2. Per-instance(实例级别独享):每个被代理对象都有自己独立的 Advice 实例。

举个例子:

类型适用场景举例
Per-class不依赖目标对象状态的通用逻辑事务管理、日志记录
Per-instance要为每个对象维护额外状态“锁”功能(如 Lockable 接口),每个对象有自己的 locked 状态

重点:你可以混合使用两种模式,比如一个 AOP 代理中既有共享的事务 advice,也有每个实例独有的“锁定”功能。


6.2.2 Spring 中的 Advice 类型

Spring 提供了多种标准 Advice 类型,并支持扩展。以下是五种主要类型:


1️⃣ Around Advice(环绕通知)——最强大的类型

✅ 特点:
  • 最灵活,能控制方法调用前后的行为。
  • 必须实现 MethodInterceptor 接口。
  • 可以决定是否继续执行原方法(proceed())。
  • 可以修改返回值或抛出异常。
📌 接口定义(Java):
public interface MethodInterceptor extends Interceptor {Object invoke(MethodInvocation invocation) throws Throwable;
}
🔍 参数说明:
  • invocation: 包含目标方法、参数、目标对象、代理对象等信息。
  • invocation.proceed(): 继续执行下一个拦截器或目标方法。
💡 示例:打印方法调用前后日志
public class DebugInterceptor implements MethodInterceptor {public Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("Before: " + invocation.getMethod());Object result = invocation.proceed(); // 执行目标方法System.out.println("After: method returned " + result);return result;}
}

注意

  • 如果你不调用 proceed(),目标方法就不会执行。
  • 少数情况下可以返回替代值或抛异常,但一般建议调用 proceed()

📌 优势:与 AOP Alliance 兼容,可在其他 AOP 框架中复用。


2️⃣ Before Advice(前置通知)

✅ 特点:
  • 在方法执行前运行。
  • 不能改变返回值。
  • 若抛异常,则中断流程,不再执行后续拦截器和目标方法。
📌 接口定义:
public interface MethodBeforeAdvice extends BeforeAdvice {void before(Method m, Object[] args, Object target) throws Throwable;
}
💡 示例:统计方法调用次数
public class CountingBeforeAdvice implements MethodBeforeAdvice {private int count = 0;public void before(Method m, Object[] args, Object target) {count++;}public int getCount() {return count;}
}

优点:简单安全,无需处理 proceed(),不会忘记调用。

📌 可配合任意 Pointcut 使用。


3️⃣ Throws Advice(异常通知)

✅ 特点:
  • 方法抛出异常后触发。
  • 无接口标记型接口(tag interface),不需要实现具体方法。
  • 通过反射查找名为 afterThrowing(...) 的方法来绑定逻辑。
📌 方法签名格式:
void afterThrowing([Method, args, target], 异常类型)
  • 参数可选,但最后一个必须是异常类型。
  • 可以有 1 个或 4 个参数。
💡 示例1:捕获 RemoteException
public class RemoteThrowsAdvice implements ThrowsAdvice {public void afterThrowing(RemoteException ex) {System.out.println("Remote error occurred: " + ex.getMessage());}
}
💡 示例2:获取更多上下文
public class ServletThrowsAdviceWithArguments implements ThrowsAdvice {public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {System.out.println("Failed in method: " + m.getName());}
}
💡 合并多个异常处理
public class CombinedThrowsAdvice implements ThrowsAdvice {public void afterThrowing(RemoteException ex) { ... }public void afterThrowing(Method m, Object[], Object, ServletException ex) { ... }
}

⚠️ 重要警告

  • 如果 afterThrowing 方法自身抛出异常,会覆盖原始异常
  • 抛出检查异常(checked exception)时,必须与目标方法声明一致,否则会包装成运行时异常。

📌 可配合任意 Pointcut 使用。


4️⃣ After Returning Advice(后置返回通知)

✅ 特点:
  • 方法成功执行并返回后执行。
  • 不能修改返回值。
  • 若自身抛异常,会中断流程。
📌 接口定义:
public interface AfterReturningAdvice extends Advice {void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable;
}
💡 示例:统计成功调用次数
public class CountingAfterReturningAdvice implements AfterReturningAdvice {private int count = 0;public void afterReturning(Object returnValue, Method m, Object[] args, Object target) {count++;}public int getCount() {return count;}
}

📌 与 Before Advice 类似,但只在成功返回时触发。

📌 可配合任意 Pointcut 使用。


5️⃣ Introduction Advice(引入通知)——特殊类型

✅ 特点:
  • 为一个类动态添加新的接口和行为(即“混入 mixin”)。
  • 属于“类级别”的增强,不是方法级别。
  • 例如:让任何对象都能变成“可锁定”的(Lockable)。
🧩 涉及组件:
  1. IntroductionInterceptor: 实现新接口的方法逻辑。
  2. IntroductionAdvisor: 将 IntroductionInterceptor 和目标类关联起来。
📌 接口定义:
public interface IntroductionInterceptor extends MethodInterceptor {boolean implementsInterface(Class intf);
}
💡 实战示例:实现 Lockable 接口

目标:让任意对象支持 .lock().unlock(),锁定后禁止调用 setter 方法。

Step 1: 定义接口
public interface Lockable {void lock();void unlock();boolean locked();
}
Step 2: 创建 IntroductionInterceptor(使用 DelegatingIntroductionInterceptor)
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {private boolean locked = false;public void lock() { this.locked = true; }public void unlock() { this.locked = false; }public boolean locked() { return this.locked; }// 拦截所有方法调用public Object invoke(MethodInvocation invocation) throws Throwable {if (locked && invocation.getMethod().getName().startsWith("set")) {throw new IllegalStateException("Object is locked!");}return super.invoke(invocation); // 调用父类逻辑(自动分发到 introduced 方法)}
}

📌 关键点:

  • DelegatingIntroductionInterceptor 会自动把 Lockable 接口的方法调用转发给当前对象。
  • 自定义 invoke() 是为了拦截 setter 方法。
Step 3: 创建 Advisor
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {public LockMixinAdvisor() {super(new LockMixin(), Lockable.class);}
}

✅ 这样就完成了“为任意对象添加 Lockable 功能”。

📌 注意:

  • Introduction 不能用普通 Pointcut,因为它作用于类而非方法。
  • 必须使用 IntroductionAdvisor
  • 通常是 per-instance 的,因为每个对象可能有自己的状态(如 locked)。

6.3 Advisor API in Spring

Advisor = 一个 Pointcut + 一个 Advice

换句话说:

  • Advice 告诉你“做什么”(what to do)。
  • Pointcut 告诉你“在哪里做”(where to do it)。
  • Advisor 把两者结合起来。

常见实现类:

org.springframework.aop.support.DefaultPointcutAdvisor

它可以组合:

  • 任意 Pointcut(如 NameMatchMethodPointcut
  • 任意 Advice(Before、After、Throws、Around)

✅ 关键能力:

你可以在同一个 AOP 代理中混合使用多种 Advice!

例如:

<!-- XML 配置示例 -->
<aop:config><aop:advisor advice-ref="txAdvice" pointcut="execution(* save*(..))"/><aop:advisor advice-ref="loggingBefore" pointcut="execution(* *.*(..))"/><aop:advisor advice-ref="countingAfter" pointcut="execution(* find*(..))"/><aop:advisor advice-ref="lockAdvisor" /> <!-- 引入 advisor -->
</aop:config>

Spring 会自动构建拦截器链(Interceptor Chain),按顺序执行。


🎯 总结:一张表帮你理清所有 Advice 类型

Advice 类型触发时机是否能修改流程是否能访问返回值/异常是否需要 proceed()典型用途
Around方法前后✅ 能(可跳过、改返回值)✅ 能✅ 必须手动调用权限控制、缓存、性能监控
Before方法前❌ 不能改返回值
✅ 可中断(抛异常)
❌ 不能❌ 不需要日志、参数校验
After Returning方法成功返回后❌ 不能改返回值
✅ 可中断(抛异常)
✅ 能读返回值❌ 不需要统计成功次数、清理资源
Throws方法抛异常后✅ 能覆盖异常✅ 能访问异常对象❌ 不需要错误日志、重试、降级
Introduction类级别增强✅ 能添加新接口和状态✅ 能✅ 需要(但通常用父类实现)Mixin(混入)、动态增强对象能力

🧠 如何选择合适的 Advice?

需求推荐 Advice
记录方法开始Before Advice
记录方法结束(无论成败)Around Advice(finally 块)
记录方法成功返回After Returning
捕获并处理异常Throws Advice
包装整个方法(如事务、缓存)Around Advice
给对象加新功能(如 Lockable)Introduction Advice

✅ 最佳实践建议

  1. 优先使用更具体的 Advice 类型(如 Before/After),代码更清晰。
  2. 如果要跨框架兼容,使用 MethodInterceptor(Around)
  3. Introduction 是高级功能,谨慎使用,注意状态管理(per-instance)
  4. Avoid 在 Advice 中抛出不必要的检查异常,以免破坏签名兼容性。
  5. 结合 Pointcut 使用 Advisor 来精确控制织入位置

如果你正在学习 Spring AOP 或准备面试,这一部分内容非常关键。掌握这些 Advice 的区别和使用场景,就能写出更优雅、更可控的切面逻辑。

需要我根据这个内容画一张 思维导图结构图 或者给出一个 完整的 Spring AOP 配置示例(XML + 注解) 吗?欢迎继续提问!

http://www.dtcms.com/a/533398.html

相关文章:

  • 服装网站案例完整个人网站html
  • 北网站建设商城网站建
  • OpenWrt搭建私有源
  • RxJava在Android开发中的实战指南
  • 网站建设询价公告英文视频网站如何做外链
  • 东莞做网站需要避免这些因素网站开发的关键
  • [人工智能-大模型-89]:大模型底层依赖层/支撑层技术栈 - 多卡并行支持,NVLink、InfiniBand 高速互联网络
  • 嘉兴城乡建设局网站网站服务器如何管理
  • 四川省建设主管部门网站珠海市香洲区建设局网站
  • 【day11】技巧+链表
  • 临汾做网站长沙网站优化推广方案
  • 网站建设代理政策网站支持qq登录怎么做
  • 网站后缀ga蜂鸟影院高清免费观看
  • 童装网站建设目标分销系统合法吗
  • 如何解决pytorch下载缓慢问题
  • 广州小网站建设小网站广告投放
  • 网站制作哪个好一些电商营销策略方案
  • Ubuntu24.04
  • 广州市网站建设服务机构中山哪里有做网站
  • 网站模板 php沈阳网站建设q479185700棒
  • 学校培训网站开发做啊网站
  • CodeBuddy助力开发:从想法到落地的全流程体验
  • 1.4.1 大数据方法论与实践指南-元数据治理
  • 广东省省考备考(第一百二十六天10.17)——申论(第六节课)
  • 有个网站做字的图片qq登录wordpress
  • 005-Spring AI Alibaba Structured Output 功能完整案例
  • 私密性最好的浏览器营销网站优化推广
  • 电商网页精品欣赏网站企业管理培训课程机构
  • 中国住房建设网官方网站博客主题 wordpress
  • TVM | TupleNode / TupleGetItemNode