PDF大白话说Java面试题 — 06_Spring篇第10题解释一下 Spring AOP 里面的几个名词回答核心考点 Spring AOP 的名词体系是理解 AOP 的基石大厂面试不会只问有哪几个名词而是深入考察每个名词的源码级实现如AspectJExpressionPointcut如何解析表达式、五种通知类型的执行顺序与异常传播、织入的三种时机与 Spring 的选择原因、以及JoinPoint与ProceedingJoinPoint的区别。面试官真正想判断的是你是否建立了从概念到源码的完整认知链路能否在工程实践中准确运用这些概念设计和排查问题。1. 切面Aspect1.1 定义与本质切面是横切关注点的模块化封装包含一组**通知Advice和切入点Pointcut**的集合。在 Spring 中切面通过Aspect注解标识由 Spring 容器管理。AspectComponentpublicclassLoggingAspect{// 切入点定义Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceMethods(){}// 通知定义Before(serviceMethods())publicvoidlogBefore(JoinPointjoinPoint){System.out.println([日志切面] 方法开始: joinPoint.getSignature().getName());}}1.2 切面的生命周期阶段说明对应源码解析Spring 扫描Aspect注解解析切点表达式AspectJAutoProxyCreator注册将切面 Bean 注册到BeanFactoryBeanDefinitionRegistry代理创建根据切点匹配结果为目标 Bean 创建代理AbstractAutoProxyCreator织入将通知织入到代理对象的方法调用链JdkDynamicAopProxy/CglibAopProxy1.3 多切面优先级控制当多个切面同时匹配同一连接点时通过Order注解或实现Ordered接口控制执行顺序AspectOrder(1)// 数值越小优先级越高越先执行publicclassSecurityAspect{...}AspectOrder(2)publicclassLogAspect{...}执行顺序规则优先级高的切面的Before先执行但After后执行类似栈结构。2. 连接点Join Point2.1 定义与范围连接点是程序执行过程中的某个特定点是 AOP 可以插入逻辑的位置。在 Spring AOP 中连接点仅限于方法调用因为 Spring AOP 基于代理实现。AOP 框架支持的连接点类型Spring AOP仅方法调用AspectJ方法调用、构造器调用、字段访问、异常处理等2.2 JoinPoint 对象详解JoinPoint是 Spring AOP 提供的运行时对象封装了当前连接点的全部信息Before(serviceMethods())publicvoidlogBefore(JoinPointjoinPoint){// 获取目标对象ObjecttargetjoinPoint.getTarget();// 获取代理对象ObjectproxyjoinPoint.getThis();// 获取方法签名MethodSignaturesignature(MethodSignature)joinPoint.getSignature();Methodmethodsignature.getMethod();// 获取方法名StringmethodNamesignature.getName();// 获取参数Object[]argsjoinPoint.getArgs();// 获取参数类型Class?[]paramTypessignature.getParameterTypes();}JoinPoint API说明getTarget()获取被代理的目标对象原始对象getThis()获取代理对象本身getSignature()获取连接点的签名方法签名getArgs()获取方法参数数组getKind()获取连接点类型如method-executiontoLongString()获取完整的方法描述2.3 ProceedingJoinPoint——环绕通知专用ProceedingJoinPoint是JoinPoint的子接口仅用于Around通知增加了proceed()方法控制目标方法的执行Around(serviceMethods())publicObjectlogAround(ProceedingJoinPointpjp)throwsThrowable{// 前置逻辑longstartSystem.currentTimeMillis();// 执行目标方法关键不调用则目标方法不会执行Objectresultpjp.proceed();// 也可以修改参数pjp.proceed(new Object[]{newArg1, newArg2});// 后置逻辑longcostSystem.currentTimeMillis()-start;System.out.println(方法耗时: costms);// 可以修改返回值returnresult;}⚠️ 重要Around通知中必须调用proceed()否则目标方法不会执行。这是最常见的环绕通知使用错误。3. 切入点Pointcut3.1 定义与本质切入点是匹配连接点的表达式定义了在哪里织入通知。Spring AOP 使用 AspectJ 的切点表达式语法。3.2 切点表达式语法详解execution(修饰符 返回类型 包名.类名.方法名(参数) 异常)组成部分说明示例修饰符可选public/private/protectedpublic返回类型必填*表示任意*、void、String包名必填.表示当前包..表示任意子包com.service、com..service类名必填*表示任意UserService、*Service方法名必填*表示任意addUser、*参数必填()无参、(..)任意、(*, String)指定(Long)、(String, ..)异常可选throws IOException常用表达式示例Pointcut(execution(public * com.example.service.*.*(..)))// service包下所有public方法Pointcut(execution(* com.example.service..*.*(..)))// service包及其子包下所有方法Pointcut(execution(* com.example.service.UserService.add*(..)))// UserService中以add开头的方法Pointcut(execution(* com.example.service.*Service.*(..)))// 以Service结尾的类中的所有方法Pointcut(execution(* com.example.service.*.*(Long, ..)))// 第一个参数为Long的方法Pointcut(execution(* com.example.service.*.*(..)) throws Exception)// 声明抛出Exception的方法3.3 其他切点指示器指示器说明示例annotation匹配带有指定注解的方法annotation(com.example.Log)within匹配指定类型内的方法within(com.example.service.*)this匹配代理对象为指定类型的this(com.example.service.UserService)target匹配目标对象为指定类型的target(com.example.service.UserService)args匹配参数为指定类型的args(java.lang.String)bean匹配指定 Bean 名称bean(userService)within匹配类上有指定注解的within(com.example.Service)target匹配目标对象类上有指定注解的target(com.example.Service)args匹配参数类上有指定注解的args(com.example.Valid)组合表达式Pointcut(execution(* com.example.service.*.*(..)) annotation(com.example.Log))publicvoidloggedServiceMethods(){}// 匹配service包下且带有Log注解的方法Pointcut(execution(* com.example.service.*.*(..)) || execution(* com.example.controller.*.*(..)))publicvoidserviceOrController(){}// 匹配service或controller包下的方法3.4 切点解析的底层实现Spring 使用AspectJExpressionPointcut解析切点表达式底层依赖 AspectJ 的PointcutParser// Spring 源码简化示意publicclassAspectJExpressionPointcutimplementsPointcut{privateStringexpression;// 切点表达式字符串Overridepublicbooleanmatches(Methodmethod,Class?targetClass){// 使用 AspectJ 的 PointcutExpression 进行匹配PointcutExpressionpcExpressionpointcutParser.parsePointcutExpression(expression);returnpcExpression.matchesMethodExecution(method).alwaysMatches();}}4. 通知Advice4.1 五种通知类型深度解析通知类型注解执行时机特点典型场景前置通知Before目标方法执行前无法阻止方法执行权限校验、参数校验后置通知After目标方法执行后无论是否异常类似 finally资源释放、清理返回通知AfterReturning目标方法正常返回后可获取返回值日志记录、缓存更新异常通知AfterThrowing目标方法抛出异常后可获取异常对象异常告警、补偿逻辑环绕通知Around目标方法执行前后完全控制执行流程事务管理、性能监控4.2 通知执行顺序详解单一切面内的执行顺序Around 前半部分proceed() 之前 ↓ Before ↓ 【目标方法执行】 ↓ AfterReturning正常返回或 AfterThrowing抛出异常 ↓ After无论是否异常最终执行 ↓ Around 后半部分proceed() 之后异常场景下的执行顺序Around 前半部分 ↓ Before ↓ 【目标方法执行 → 抛出异常】 ↓ AfterThrowing捕获异常 ↓ After仍然执行 ↓ Around 后半部分异常会传播到此处需处理⚠️ 注意After类似于finally无论是否异常都会执行。Around中如果proceed()抛出异常异常会传播到Around的后半部分。4.3 通知的参数绑定Spring AOP 支持将连接点信息绑定到通知方法的参数// 绑定返回值AfterReturning(pointcutserviceMethods(),returningresult)publicvoidlogAfterReturning(Objectresult){System.out.println(方法返回: result);}// 绑定异常AfterThrowing(pointcutserviceMethods(),throwingex)publicvoidlogAfterThrowing(Exceptionex){System.out.println(方法异常: ex.getMessage());}// 绑定注解Before(annotation(log))publicvoidlogWithAnnotation(Loglog){System.out.println(注解值: log.value());}// 绑定参数Before(execution(* com.example.service.*.*(Long,..)) args(id,..))publicvoidlogWithParam(Longid){System.out.println(参数ID: id);}4.4 通知的异常传播通知类型异常处理行为Before抛出异常会阻止目标方法执行AfterReturning抛出异常会覆盖目标方法的正常返回最终向外抛出AfterThrowing抛出异常会覆盖原始异常最终向外抛出After抛出异常会覆盖原始异常如果存在最终向外抛出Around完全控制异常可捕获、可抛出、可转换5. 织入Weaving5.1 定义与三种织入时机织入是将切面应用到目标对象的过程即把通知逻辑插入到连接点的过程。AOP 规范定义了三种织入时机织入时机英文实现方式特点代表框架编译期织入Compile-time weaving特殊的编译器在编译时修改源码无运行时开销需特殊编译器AspectJ AJC加载期织入Load-time weaving类加载器在加载类时修改字节码无运行时开销需特殊类加载器AspectJ LTW运行期织入Runtime weaving运行时动态生成代理对象有代理开销使用简单Spring AOP5.2 Spring AOP 为什么选择运行期织入Spring AOP 选择运行期织入动态代理的原因无侵入性无需修改编译器或类加载器纯 Java 实现与 IoC 集成利用 Spring 容器管理 Bean 的生命周期在 Bean 初始化后创建代理使用简单注解驱动零配置即可使用满足大多数场景企业应用中 95% 的 AOP 需求是方法拦截运行期织入足够。代价每次方法调用都经过代理有一定性能开销但通常可忽略。5.3 Spring AOP 织入的源码流程Bean 实例化 ↓ Bean 属性填充依赖注入 ↓ Bean 初始化PostConstruct、InitializingBean ↓ 【关键】AbstractAutoProxyCreator.postProcessAfterInitialization() ↓ 检查 Bean 是否匹配任何切点 ↓ 是 → 创建代理对象JDK 或 CGLIB替换原始 Bean ↓ 否 → 返回原始 Bean ↓ 代理对象注入到依赖方6. 目标对象Target与代理Proxy6.1 目标对象Target被代理的原始对象即业务逻辑的真正执行者。在 Spring AOP 中目标对象通常是 Spring 容器管理的 Bean。6.2 代理ProxyAOP 框架生成的代理对象客户端实际持有的引用。代理对象拦截方法调用在适当位置执行通知逻辑。代理类型实现方式适用场景JDK 动态代理实现目标接口目标类实现了接口CGLIB 代理继承目标类目标类未实现接口或强制使用6.3 目标对象 vs 代理对象的区别AutowiredprivateUserServiceuserService;// 注入的是代理对象publicvoidtest(){// userService 是代理对象JDK 代理时类型为 $ProxyXXCGLIB 时为 UserService$$EnhancerBySpringCGLIBuserService.addUser();// 调用经过代理触发切面// 获取目标对象if(AopUtils.isAopProxy(userService)){UserServicetarget(UserService)AopProxyUtils.ultimateTargetClass(userService);}}7. 引入Introduction引入是 Spring AOP 的一个高级特性允许为目标对象动态添加新的接口实现DeclareParents(valuecom.example.service.*,defaultImplDefaultUsageTracked.class)privateUsageTrackedmixin;// 为所有 Service 类动态添加 UsageTracked 接口实现特性说明作用动态为目标类添加新接口无需修改源码实现通过代理对象实现多个接口场景为现有类添加监控、统计等功能8. 面试官追问与高分回答模板追问 1“Spring AOP 中有哪些关键名词分别是什么意思”低分回答“有切面、连接点、切入点、通知、织入。切面是模块化的横切关注点连接点是程序执行的特定点切入点是匹配连接点的表达式通知是切面执行的动作织入是将切面应用到目标对象的过程。”背诵式回答没有深度高分回答Spring AOP 的核心名词体系包括切面Aspect横切关注点的模块化封装包含通知和切入点。在 Spring 中通过Aspect注解标识由Order控制多切面优先级。连接点Join Point程序执行过程中的特定点Spring AOP 中仅限于方法调用。JoinPoint对象封装了目标对象、代理对象、方法签名、参数等信息ProceedingJoinPoint是其子接口专用于Around通知提供proceed()控制目标方法执行。切入点Pointcut匹配连接点的表达式使用 AspectJ 语法。核心指示器包括execution方法匹配、annotation注解匹配、within类型匹配、beanBean 名称匹配等支持、||、!组合。通知Advice切面在连接点执行的动作共五种类型Before方法执行前After方法执行后无论是否异常类似 finallyAfterReturning方法正常返回后可获取返回值AfterThrowing方法抛出异常后可获取异常Around环绕方法执行完全控制流程必须调用proceed()织入Weaving将切面应用到目标对象的过程。Spring AOP 采用运行期织入动态代理通过AbstractAutoProxyCreator在 Bean 初始化后检查切点匹配创建代理对象替换原始 Bean。目标对象Target被代理的原始对象。代理ProxyAOP 生成的代理对象客户端实际持有的引用负责拦截方法调用并执行通知链。理解这些名词的关键是建立’在哪里Pointcut→ 做什么Advice→ 怎么做Proxy/Weaving的完整链路。追问 2“五种通知类型的执行顺序是什么异常时怎么执行”高分回答正常执行顺序Around 前半 → Before → 目标方法 → AfterReturning → After → Around 后半异常执行顺序Around 前半 → Before → 目标方法抛异常→ AfterThrowing → After → Around 后半异常传播关键要点After类似finally无论是否异常都会执行AfterReturning和AfterThrowing互斥只会执行其一Around中如果proceed()抛出异常异常会传播到Around的后半部分可以在Around中捕获并处理多切面通过Order控制顺序数值越小优先级越高Before先执行但After后执行。追问 3“JoinPoint 和 ProceedingJoinPoint 有什么区别”高分回答ProceedingJoinPoint是JoinPoint的子接口核心区别特性JoinPointProceedingJoinPoint使用场景所有通知类型除Around仅Around通知控制目标方法❌ 无法控制✅ 通过proceed()控制执行修改参数❌✅proceed(Object[] args)修改返回值❌✅ 可替换proceed()的返回值阻止执行❌✅ 不调用proceed()即可阻止JoinPoint提供只读信息目标对象、方法签名、参数等ProceedingJoinPoint增加了proceed()方法这是Around通知能够’环绕’目标方法的核心。⚠️ 常见错误在Around中忘记调用proceed()导致目标方法不执行。追问 4切点表达式 execution(com.service..(…)) 每个部分是什么意思*高分回答execution(* com.service.*.*(..))的语法结构是execution(修饰符 返回类型 包名.类名.方法名(参数) 异常)逐部分解析execution切点指示器按方法签名匹配第一个*返回类型表示任意返回类型com.service包名精确匹配com.service包第二个*类名表示任意类第三个*方法名表示任意方法(..)参数表示任意参数零个或多个。整体含义匹配com.service包下任意类的任意方法不限返回类型和参数。常用通配符*匹配一个任意字符包名中用一个点类名/方法名中匹配任意..匹配零个或多个任意字符包名中表示任意子包参数中表示任意参数匹配当前类及其子类。追问 5“Spring AOP 为什么只能在运行时织入AspectJ 是怎么织入的”高分回答Spring AOP 选择运行期织入动态代理的原因纯 Java 实现无需修改编译器或 JVM与 Spring IoC 无缝集成使用简单注解驱动零配置满足大多数需求企业应用 95% 的 AOP 需求是方法拦截。AspectJ 支持三种织入时机编译期织入使用 AspectJ 编译器AJC在编译时修改源码字节码无运行时开销加载期织入LTW通过-javaagent和特殊类加载器在类加载时修改字节码运行期织入与 Spring AOP 类似。Spring AOP 的织入流程Bean 初始化后 →AbstractAutoProxyCreator.postProcessAfterInitialization()检查切点匹配 → 匹配则创建代理对象JDK/CGLIB→ 代理对象替换原始 Bean 注入到依赖方。代价每次方法调用经过代理有一定性能开销。但方法调用本身的 overhead 远大于代理开销通常可忽略。追问 6“Around 通知中 proceed() 的作用是什么不调用会怎样”高分回答proceed()是Around通知的核心方法作用是执行目标方法或下一个通知。在Around中proceed()的调用位置决定了通知的’环绕’特性Around(serviceMethods())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{// 前置逻辑proceed() 之前System.out.println(Before);Objectresultpjp.proceed();// ← 执行目标方法// 也可以传参pjp.proceed(new Object[]{arg1, arg2});// 后置逻辑proceed() 之后System.out.println(After);returnresult;}不调用proceed()的后果目标方法不会执行如果这是事务切面事务不会开启如果这是日志切面只会记录’方法开始’不会记录’方法结束’。高级用法修改参数pjp.proceed(new Object[]{modifiedArg})修改返回值在proceed()后修改result异常处理用try-catch包裹proceed()捕获并转换异常。9. 方案选型速查表业务场景推荐通知类型核心理由权限校验Before方法执行前拦截失败直接拒绝日志记录Around精确计算耗时记录入参和出参事务管理Around完全控制事务边界可捕获异常回滚缓存管理Around先查缓存无则执行并写入异常告警AfterThrowing仅异常时触发避免正常流程干扰资源释放After类似 finally确保一定执行返回值处理AfterReturning正常返回时处理如数据脱敏方法重试Around捕获异常后循环重试面试官想要的满分总结Spring AOP 的七大核心名词构成了完整的 AOP 概念体系切面Aspect是横切关注点的模块化封装包含通知和切入点连接点Join Point是程序执行的特定点Spring 中仅限方法调用切入点Pointcut通过 AspectJ 表达式定义在哪里织入通知Advice定义做什么共五种类型按Around→Before→ 目标方法 →AfterReturning/AfterThrowing→After的顺序执行织入Weaving是应用切面的过程Spring 选择运行期动态代理实现目标对象Target是被代理的原始对象代理Proxy是客户端实际持有的代理对象。理解这些名词的关键是建立从概念到源码的链路切点表达式由AspectJExpressionPointcut解析通知执行由ReflectiveMethodInvocation驱动代理创建由DefaultAopProxyFactory根据目标类是否实现接口选择 JDK 或 CGLIB。生产中最容易踩的坑是Around中忘记调用proceed()导致目标方法不执行以及混淆JoinPoint只读和ProceedingJoinPoint可控的适用场景。记住Around是最强大的通知类型也是最容易出错的类型。觉得对您有帮助麻烦点点关注啦您的关注是我创作的最大动力~