软考高级系统架构师之Spring AOP篇

📅 2026/7/8 3:23:00
软考高级系统架构师之Spring AOP篇
⚡ Spring AOP 核心导读Spring AOPAspect-Oriented Programming—— Spring 框架的核心模块之一通过动态代理在运行时将横切关注点日志、事务、权限等无侵入地织入业务方法是 OOP 的有力补充。分离关注点业务逻辑与系统服务解耦运行时织入基于 JDK/CGLIB 动态代理无需修改源码方法级拦截支持 5 种通知类型精准控制执行时机注解驱动AspectPointcut极简配置与 Spring Boot 无缝集成 一句话Spring AOP 动态代理 切点表达式 通知让你在不入侵业务代码的前提下统一处理日志、事务、权限等“横切”逻辑。系统架构师学习平台点击这里进入 一、AOP 核心术语必须掌握术语英文通俗解释类比切面Aspect横切关注点的模块化单元 切入点 通知如“日志模块”、“事务模块”连接点Join Point程序执行中所有可能被拦截的点Spring 中仅指方法执行所有路口切入点Pointcut通过表达式精准匹配出来的实际拦截点设有红绿灯的路口通知Advice在特定切入点执行的增强代码定义何时 做什么红绿灯规则停/行目标对象Target被增强的原始业务对象被管理的车辆代理对象ProxyAOP 框架动态创建的对象包含增强逻辑交警指挥车辆织入Weaving将切面应用到目标对象并生成代理的过程安装交通系统的动作引入Introduction动态为现有类添加新方法/属性给车辆加装新设备 二、五种通知类型Advice—— 拦截时机的艺术通知类型注解执行时机典型用途前置通知Before目标方法执行之前参数校验、操作日志、权限预检后置通知After目标方法执行之后无论是否异常释放资源、关闭连接返回通知AfterReturning目标方法正常返回后可获取返回值记录响应数据、缓存更新异常通知AfterThrowing目标方法抛出异常后统一异常捕获、错误告警环绕通知Around包围目标方法可控制是否执行及参数返回值性能监控、事务管理、重试机制⚠️ 原则能用弱类型通知就别用环绕通知Around最强大但最容易出错需手动proceed()。 三、切点表达式Pointcut—— 精准定位的艺术Spring AOP 采用AspectJ 切点表达式最常用的是execution。基本语法execution(修饰符? 返回类型 类全限定名.方法名(参数) 异常?)常见示例表达式示例含义execution(* com.example.service.*.*(..))匹配 service 包下所有类的所有方法execution(public * com.example.service.UserService.*(..))匹配 UserService 的 public 方法execution(* com.example.service..*.*(..))匹配 service 包及子包所有方法execution(* find*(..))匹配所有以find开头的方法execution(* com.example.service.UserService.findUser(Long, ..))匹配第一个参数为 Long 的 findUser 方法常用切点指示符PCDexecution匹配方法执行最常用within匹配指定包/类中的所有方法annotation匹配带有特定注解的方法bean匹配特定 Spring Bean 名称⚙️ 四、实现原理 —— JDK 动态代理 vs CGLIBSpring AOP 根据目标类是否实现接口自动选择代理机制代理方式适用场景实现机制特点JDK 动态代理目标类实现了接口java.lang.reflect.ProxyInvocationHandler基于接口轻量JDK 原生CGLIB 代理目标类未实现接口通过字节码技术生成子类继承不需要接口但不能代理final方法 注意Spring AOP只支持方法级连接点无法拦截字段访问/构造器执行这是由动态代理的天然限制决定的。 五、配置方式注解驱动为主流1. 引入依赖Spring BootdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency2. 启用 AOPSpring Boot自动开启EnableAspectJAutoProxy默认生效传统 Spring在配置类上添加EnableAspectJAutoProxy3. 编写切面示例代码ComponentAspectSlf4jpublicclassLoggingAspect{// 1. 定义切入点复用Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceLayer(){}// 2. 前置通知Before(serviceLayer())publicvoidlogBefore(JoinPointjp){log.info(调用方法{}参数{},jp.getSignature().getName(),jp.getArgs());}// 3. 环绕通知性能监控Around(serviceLayer())publicObjectmeasureTime(ProceedingJoinPointpjp)throwsThrowable{longstartSystem.currentTimeMillis();Objectresultpjp.proceed();// 执行目标方法longcostSystem.currentTimeMillis()-start;log.info(方法 {} 耗时 {} ms,pjp.getSignature().getName(),cost);returnresult;}} 也可使用 XML 配置现不常用注解方式已主导。 六、实际落地场景真实项目必备场景通知类型建议说明操作日志记录BeforeAfterReturning记录请求参数、响应结果、操作人声明式事务管理AroundSpringTransactional底层基于 AOP权限校验RBACBefore方法执行前检查当前用户是否有权访问接口耗时监控Around统计慢接口上报监控系统统一异常处理AfterThrowing捕获业务异常封装成统一返回格式缓存管理CacheableAround方法执行前查缓存执行后更新缓存数据脱敏/加密AfterReturning对返回的敏感字段手机号、身份证脱敏重试机制Around方法失败后自动重试如调用外部 API 七、Spring AOP 与 AspectJ 对比维度Spring AOPAspectJ织入时机运行时动态代理编译时 / 类加载时字节码增强连接点范围仅方法执行方法、字段、构造器、静态初始化等性能有代理开销每次方法调用都走代理无运行时开销直接执行增强后的字节码易用性简单与 Spring 无缝集成需要独立编译器/编织器较复杂适用场景大多数企业级应用Web/微服务对性能极致要求或需要细粒度拦截如框架开发 实际生产中90% 场景使用 Spring AOP 就足够除非你需要拦截字段访问或追求极致性能。⚠️ 八、常见坑点 注意事项问题原因解决方案同一个类中方法调用不生效内部调用走this而非代理对象① 注入自身 Bean 调用② 使用AopContext.currentProxy()静态方法无法拦截代理无法覆盖静态方法改用 AspectJ 或手动调用final方法无法被 CGLIB 代理CGLIB 通过继承final方法不可覆写避免在代理类中使用final方法循环依赖问题AOP 代理可能引发循环依赖使用Lazy或设计上解耦切面执行顺序混乱多个切面优先级未指定使用Order注解或实现Ordered接口 九、速记汇总·一图流 核心组成切面 切入点表达式 通知5 种时机 切入点execution语法精准定位方法 代理底层有接口 → JDK无接口 → CGLIB 通知类型BeforeAfterAfterReturningAfterThrowingAround️ 常见场景日志、事务、权限、监控、缓存、重试 注意坑点内部调用不走代理静态/final 无法拦截多个切面需Order总结Spring AOP 通过运行时动态代理把日志、事务等横切逻辑从业务代码中抽离极大提升代码的复用性和可维护性。它与 Spring 生态天然融合是每个后端开发者必须熟练掌握的利器。牢记切点定位 通知织入 优雅解耦。适用场景Web 层请求日志、Service 层事务管理、DAO 层异常转换、任意需要统一增强的业务模块。