连载中 7/18

AOP(下):切面是怎么织进你代码的

2026-11-05 · 42 阅读 · 0 评论 · 0 赞

切面的三要素

写一个切面只需要三样:切点(在哪儿织)、通知(织什么)、织入(谁织)。前两个是写代码的事,第三个是 Spring 的事——上篇的代理在这里接上。

切点表达式:圈住目标

@Pointcut("execution(* com.demo.service..*.*(..))")
public void serviceLayer() {}
//      *    任意返回值
//                  ..   包及其子包
//                        *   任意类 .*  任意方法 (..) 任意参数

@Pointcut("@annotation(com.demo.anno.AuditLog)")
public void auditLog() {}     // 标了 @AuditLog 注解的方法

execution 按位置记忆:修饰符(可省)、返回值、包.类.方法、参数。业务里更推荐 @annotation 注解切点——想审计谁就标个注解,不用为每个包维护表达式,意图显式、改动局部化。

五种通知,一个万能

@Before 前置、@After 后置(finally 语义)、@AfterReturning 正常返回后、@AfterThrowing 抛异常后、@Around 环绕。Around 是唯一全能的:能改参数、改返回值、吞异常、控制目标是否执行。业务切面默认用它,其余四种按语义需要选用。

织入:切面怎么变成代理

把原理串回第 2、4 篇:@EnableAspectJAutoProxy 导入 AnnotationAwareAspectJAutoProxyCreator——正是第 4 篇四大金刚里 AbstractAutoProxyCreator 的子类。每个 Bean 走到生命周期第 7 步(初始化后)时它出面:扫描全部切面的 Advisor、按切点匹配当前 Bean——匹配上就用 JDK 或 CGLIB 生成代理,把切面逻辑翻译成一条拦截器链塞进代理。运行时调方法,链上通知依次推进,@Around 的 proceed() 就是「把链推进到下一个」。所以织入不是编译期魔法,而是启动期把 Bean 换成代理、运行期走拦截器链。声明式事务也是同一套机器——TransactionInterceptor 就是一个通知,第 8 篇展开。

实操:注解审计切面

@Aspect
@Component
public class AuditAspect {

    @Around("@annotation(auditLog)")           // 直接绑定注解实例
    public Object around(ProceedingJoinPoint pjp, AuditLog auditLog) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            Object result = pjp.proceed();
            log(auditLog.value(), true, System.currentTimeMillis() - start);
            return result;
        } catch (Throwable e) {
            log(auditLog.value(), false, System.currentTimeMillis() - start);
            throw e;                            // 务必原样抛出,别吞
        }
    }
}

两个提醒:catch 里务必原样 throw——吞了异常,业务方一脸懵,事务也跟着失明;多个切面有先后要求时用 @Order,值小的优先级高。

AOP 的机器拆完了。下一篇看它最重要的应用:声明式事务——@Transactional 为什么必须靠 AOP 加 ThreadLocal 才能转起来。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#Spring#AOP#切面#execution#Spring Boot

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10136 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9900 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9331 阅读 · 21 评论 · 287 赞