5.3 面向切面编程


5.3 面向切面编程

本节摘要:面向切面编程(AOP)把"到处都要、又不属于任何业务"的横切关注点——日志、事务、权限、限流——抽成独立模块,由元机制自动织入业务方法。本节拆解切点、通知、织入三要素,对比编译期织入、加载期织入、运行期代理三种实现时机,并用一次真实的事务切面改造演示完整收益。

横切关注的自动化

统计一下典型服务方法的代码构成:真正的业务逻辑可能只占三成,其余是开事务、写日志、查权限、记埋点、转异常。这些代码的特征是每个方法都长一样,却不属于任何业务领域——它们"横切"了整个系统。复制粘贴式的处理让业务方法淹没在仪式代码里,且任何一个环节的口径调整都要全库搜索。

AOP 的解法是把横切逻辑声明成独立单元(切面),再用元机制把它织入目标方法——业务代码保持纯业务,横切逻辑单点维护。可以把它看作 4.1 装饰器思想的系统化版本:装饰器解决"一个函数"的增强,AOP 解决"一族函数"的增强。

一、三要素:切点、通知、织入

  • 连接点与切点:连接点是程序里可插入的位置(方法调用、字段访问、异常抛出);切点(pointcut)是"选哪些连接点"的匹配表达式,例如"业务包下所有公共方法"。
  • 通知:插入的具体逻辑,按位置分为前置、后置、环绕、异常通知。环绕通知最强——它决定目标方法执不执行、何时执行、返回什么。
  • 织入:把通知塞进切点选中位置的执行过程。织入时机是 AOP 实现的分水岭(下一小节展开)。

用声明式配置表达一个事务切面(伪配置,语义对齐主流框架):

切面:事务边界 切点:service 包下所有以 transact 开头的公共方法 通知:环绕 —— 前置开启事务;正常返回则提交;抛出异常则回滚并转译

图:环绕通知的执行时序

二、织入时机:三种实现的取舍

编译期织入:编译器或后处理工具直接修改编译产物。产物自带增强,运行期零额外开销;代价是构建链路变长,增强逻辑变更需全量重编。适合性能敏感的底层框架。

加载期织入:3.4 讲过的字节码路径——类加载进内存时被改写。增强对业务完全透明,业务 jar 不需要任何感知;代价是字节码操作门槛高、需谨慎处理类加载顺序。适合容器式平台统一注入监控与治理逻辑。

运行期代理:不碰字节码,为切点目标动态生成代理对象,调用先过代理再转发(上面的时序图画的就是它)。实现最轻、最透明,是应用框架的主流选择;代价是两条边界——只能拦截"经代理的调用"(对象内部自调用会绕过代理,这是 AOP 新手最经典的翻车点),以及代理层的固定转发开销。

三种时机的选择口诀与 2.1 的时间轴一脉相承:增强逻辑稳定且性能敏感选编译期,平台级统一治理选加载期,业务级灵活声明选运行期

三、完整改造:一个方法的前后对比

背景:订单服务的创建方法里,事务、日志、耗时统计三种仪式代码与业务混写,方法体 60 行里业务只占 15 行。

操作:业务方法瘦身,横切逻辑全部声明为切面:

@Transactional(timeout = 30) // 事务切面:环绕通知 @AuditLog("订单创建") // 审计切面:前置通知 @Timed // 统计切面:环绕通知 public Order create(OrderRequest req) { validate(req); // —— 从这里开始才是业务 Order order = orderMapper.insert(req); stockService.deduct(order); return order; }

结果:方法体从 60 行降到 12 行,业务逻辑一眼可读;耗时统计口径统一调整时,只改 @Timed 切面一处。解读:改造的实质是把"每个方法自己照顾仪式"换成"容器统一代理仪式",代理对象在运行期为这套注解生成增强链——4.1 的装饰器、3.1 的注解内省、3.4 的动态代理在此完成合流。变式与提醒:切面粒度要克制,"读方法"类操作不需要事务切面,误用会白白占用连接池;切点表达式越宽泛,行为越难追溯,评审时应要求切点窄于业务包。

切面资产的登记与盘点

切面用久了会变成"看不见的基础设施"——增强行为藏在容器里,新人不知道、老人记不全。治理办法是把切面当资产登记:每个切面一条记录,写清切点范围、通知类型、生效条件、责任人。登记带来的直接收益是三份清单:影响面清单(改这个切面会波及多少方法)、叠加清单(某个方法同时挂了哪些切面,执行顺序如何)、孤儿清单(切点已匹配不到任何方法,该下线了)。评审一个新切面提案时,先查登记表看叠加情况——新切面与既有切面的顺序如果没有明确定义,这就是一个未来的生产事故。第六章翻车复盘里的"装饰器金字塔",本质上就是缺了这份登记的必然结局。

本节要点回顾

  • 问题本质:横切关注点每个方法都要、又不属于业务,复制粘贴式处理是债。
  • 三要素:切点选位置,通知给逻辑,织入做安装;环绕通知能力最强也最需克制。
  • 三种时机:编译期零开销但构建重,加载期平台级但门槛高,运行期轻量透明——按时间轴口诀选。
  • 自调用边界:对象内部自调用绕过代理,是 AOP 最经典的翻车点。
  • 合流本质:AOP 是装饰器、注解内省、动态代理三个机制的工程化合体。

三种高级抽象都见识了。下一节换上实验员白大褂:同一个需求,反射路线与生成路线正面对照,用数据说话。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U