: AOP 核心概念与注解回顾)
阅读前提示从本篇起进入 Spring AOP 阶段第 11–14 篇。本篇是「前置兜底」——把 AOP 的术语、注解、底层映射关系讲透确保你读后面三篇源码时不迷路。如果已经熟练使用Aspect可直接跳到第 12 篇但建议花 5 分钟扫一遍「概念 → 源码对象」的映射表这是本篇最有价值的部分。一、引子为什么 AOP 是 Spring 最难啃的模块之一IoC 你还能顺着refresh() → getBean → doCreateBean一步步跟AOP 的难在于——它在 Bean 创建完成之后悄悄把你的对象换成了代理对象而这套「偷梁换柱」发生在BeanPostProcessor里调用栈深、概念多、名词还特别像。很多人卡在 AOP不是不懂动态代理而是面对下面这一串词时脑内没有地图Advice、Pointcut、Advisor、Advised、Joinpoint、Weaving、Aspect、Before、MethodInterceptor、ProxyFactory……本篇的目标把这张地图画清楚并告诉你每个注解背后在源码里对应哪个对象。二、AOP 六大核心术语必须背下来术语英文一句话定义在 Spring 里的对应物连接点Joinpoint程序执行过程中「可以被切入」的点Spring 里就是方法执行Joinpoint接口 /MethodInvocation切点Pointcut从所有连接点中「筛选出哪些要织入」的规则Pointcut接口如AspectJExpressionPointcut通知Advice织入后要执行的增强逻辑前置/后置/环绕等Advice接口如MethodBeforeAdvice、Before编译成的AspectJMethodBeforeAdvice切面Aspect切点 通知的聚合「在哪切」「切了干什么」Aspect类源码中拆成Advisor集合织入Weaving把切面逻辑「缝合」进目标对象的过程创建代理时运行时织入Spring 默认引入Introduction给目标类动态添加接口与实现不常用DelegatingIntroductionInterceptor 关键认知Aspect标注的类在 Spring 启动时被BeanFactoryAspectJAdvisorsBuilder拆解成多个Advisor一个Before方法 一个 Advisor 一个 Pointcut 一个 Advice。这是「注解世界」与「源码世界」的第一道桥。三、注解快速回顾带注释示例3.1 切点表达式 PointcutAspectComponentpublicclassLogAspect{// execution 是最常用切点指示符修饰符 返回类型 包.类.方法(参数)Pointcut(execution(* com.demo.service..*.*(..)))publicvoidserviceLayer(){}// 切点方法本身为空只是个锚点// 组合切点serviceLayer 且 不在测试包Pointcut(!within(com.demo.test..*))publicvoidexcludeTest(){}}⚠️ 注意execution(* com.demo.service..*.*(..))中..表示「任意子包」*表示「任意」返回类型/方法名(..)表示「任意参数」。这是面试高频写法的必考点。3.2 五种通知注解注解执行时机对应 Advice 实现源码能否拿到返回值Before目标方法前AspectJMethodBeforeAdvice否AfterReturning目标方法正常返回后AspectJAfterReturningAdvice能通过returningAfterThrowing目标方法抛异常后AspectJAfterThrowingAdvice否但能拿到异常After目标方法结束后finally必执行AspectJAfterAdvice否Around包裹整个方法最灵活AspectJAroundAdvice能自己 returnAround(serviceLayer())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{longstartSystem.currentTimeMillis();try{returnpjp.proceed();// 这一行才真正调用目标方法}finally{System.out.println(耗时 (System.currentTimeMillis()-start));}} 结论Around是唯一能完全控制「是否调用目标方法、修改入参/返回值」的通知其余四种是固定时机的钩子。Around对应的MethodInterceptor也是责任链的基础第 14 篇详述。3.3 开启 AOP 的两个开关// 方式一纯 SpringJava ConfigConfigurationEnableAspectJAutoProxy(proxyTargetClasstrue,exposeProxytrue)publicclassAopConfig{}// 方式二Spring Boot自动开启无需手写// Spring Boot 通过 AopAutoConfiguration 自动 EnableAspectJAutoProxyproxyTargetClass true强制用CGLIB子类代理否则有接口就用 JDK 动态代理。exposeProxy true把代理对象暴露到AopContext解决同类内部自调用AOP 失效问题第 14 篇展开。四、AOP 与拦截器、过滤器的区别极易混维度FilterInterceptorSpring MVCAOPSpring作用层Servlet 容器层MVC 的 Handler 前后Bean 方法级别依赖容器依赖 Servlet 容器依赖 Spring MVC仅依赖 Spring能改 Response能能preHandle 返回 false 拦截否只增强方法典型用途字符编码、XSS 过滤登录校验、权限日志、事务、鉴权、监控 记忆法Filter 管「请求进 Servlet 之前」Interceptor 管「请求进 Controller 之前」AOP 管「方法调用本身」。粒度从粗到细。五、概念 → 源码对象的完整映射本篇核心这是读源码前的「对照表」建议截图保存Aspect 类 │ (BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors) ▼ ListAdvisor ← 一个 Before 方法 一个 Advisor │ ├─ Pointcut 部分 → AspectJExpressionPointcut (表达式) └─ Advice 部分 → AspectJMethodBeforeAdvice / AspectJAroundAdvice ... │ ▼ 都被适配成 MethodInterceptor统一责任链接口第14篇⚠️ 易错点注解里的「通知」Before等和源码里的「Advice 接口」不是一一裸对应。Spring 会把Before包装成MethodBeforeAdvice再在调用时被适配为MethodInterceptor进入责任链。理解这层「适配」是读懂 AOP 源码的钥匙。六、常见误区误区正解AOP 是在编译期改字节码Spring AOP 默认是运行时动态代理织入AspectJ 才支持编译期/类加载期Aspect类本身会被代理不会。Aspect类是被解析的「配置源」它产生 Advisor 去代理别的Bean所有 Bean 都会被 AOP 代理只有匹配到 Pointcut 的 Bean 才会被wrapIfNecessary包装第 13 篇Around不调用 proceed 也能返回不调用proceed()目标方法根本不执行需自己决定返回值逻辑 面试题自测Spring AOP 和 AspectJ 有什么区别织入时机、能力范围Before和Around在源码里分别对应哪个 Advice 实现为什么Aspect类本身不会被代理exposeProxy true解决了什么场景的问题AOP、Interceptor、Filter 三者的作用层次和粒度差异一个Aspect类里有 3 个Before方法 1 个Around方法启动后会产生几个 Advisor Debug 小技巧在BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors()打条件断点条件为 Bean 名包含你的 aspect 类名启动后观察返回的ListAdvisor数量与每个 Advisor 内的Pointcut表达式——你会直观看到「注解 → Advisor」的拆解过程。下一篇预告第 12 篇刨开EnableAspectJAutoProxy这个开关——它如何通过AspectJAutoProxyRegistrar悄悄往容器里注册一个BeanPostProcessorAnnotationAwareAspectJAutoProxyCreator从而接管所有 Bean 的代理创建。如果这篇对你有帮助欢迎点赞 · 收藏 · 关注三连支持。Spring 源码系列共 30 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。