2026/5/21 16:07:02
网站建设
项目流程
做网站的你选题的缘由是什么,比分网站制作,儿童教育机构网页设计素材,南宁网页制作一、什么是 AOP#xff1f;1.1 AOP 基本概念AOP#xff08;Aspect-Oriented Programming#xff0c;面向切面编程#xff09;是 OOP#xff08;面向对象编程#xff09;的补充和完善。OOP 引入封装、继承和多态性等概念来建立一种对象层次结构#xff0c;但当需要为多个…一、什么是 AOP1.1 AOP 基本概念AOPAspect-Oriented Programming面向切面编程是 OOP面向对象编程的补充和完善。OOP 引入封装、继承和多态性等概念来建立一种对象层次结构但当需要为多个不具有继承关系的对象引入同一个公共行为时OOP 就会显得力不从心。AOP 的核心思想将横切关注点如日志、事务、安全等从业务逻辑中分离出来实现关注点的分离。1.2 AOP 解决的问题代码分散横切关注点如日志的代码分散在多个方法中代码混乱业务逻辑中混杂着横切关注点的代码代码重复相同的横切逻辑需要在多个地方重复编写二、AOP 核心概念详解2.1 基本术语java// 切面Aspect横切关注点的模块化 Aspect Component public class LoggingAspect { // 切点Pointcut匹配连接点的表达式 Pointcut(execution(* com.example.service.*.*(..))) public void serviceLayer() {} // 通知Advice在特定连接点执行的动作 Before(serviceLayer()) public void logBefore(JoinPoint joinPoint) { // 增强逻辑 } }核心概念解析切面Aspect横切关注点的模块化在 Spring AOP 中通常用Aspect注解标记连接点Joinpoint程序执行过程中的某个特定点如方法调用、异常抛出等切点Pointcut匹配连接点的谓词表达式确定在哪些连接点应用通知通知Advice在切点处执行的动作分为前置通知Before在方法执行前执行后置通知After在方法执行后执行无论是否异常返回通知AfterReturning方法成功执行后执行异常通知AfterThrowing方法抛出异常后执行环绕通知Around包围连接点可以控制是否执行连接点目标对象Target Object被一个或多个切面通知的对象AOP 代理AOP Proxy由 AOP 框架创建的对象用于实现切面契约织入Weaving将切面应用到目标对象创建代理对象的过程三、Spring AOP 的实现原理3.1 核心实现机制Spring AOP 主要使用两种方式实现动态代理3.1.1 JDK 动态代理基于接口适用场景目标类实现了接口java// JDK 动态代理示例 public class JdkDynamicProxyDemo { public interface UserService { void save(); } public static class UserServiceImpl implements UserService { public void save() { System.out.println(保存用户); } } public static class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target target; } Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(前置通知); Object result method.invoke(target, args); System.out.println(后置通知); return result; } } public static void main(String[] args) { UserService target new UserServiceImpl(); UserService proxy (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new MyInvocationHandler(target) ); proxy.save(); } }3.1.2 CGLIB 动态代理基于子类适用场景目标类没有实现接口java// CGLIB 动态代理示例 public class CglibProxyDemo { public static class UserService { public void save() { System.out.println(保存用户); } } public static class MyMethodInterceptor implements MethodInterceptor { Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println(前置通知); Object result proxy.invokeSuper(obj, args); System.out.println(后置通知); return result; } } public static void main(String[] args) { Enhancer enhancer new Enhancer(); enhancer.setSuperclass(UserService.class); enhancer.setCallback(new MyMethodInterceptor()); UserService proxy (UserService) enhancer.create(); proxy.save(); } }3.2 Spring AOP 代理选择策略java// Spring 中的代理创建逻辑简化版 public class DefaultAopProxyFactory implements AopProxyFactory { Override public AopProxy createAopProxy(AdvisedSupport config) { // 1. 如果配置了优化或直接指定使用CGLIB则使用CGLIB if (config.isOptimize() || config.isProxyTargetClass()) { return new CglibAopProxy(config); } // 2. 如果目标对象有接口使用JDK动态代理 Class?[] interfaces config.getProxiedInterfaces(); if (interfaces.length 0) { return new JdkDynamicAopProxy(config); } // 3. 否则使用CGLIB return new CglibAopProxy(config); } }四、Spring AOP 工作流程深度解析4.1 整体架构text1. 解析 Aspect 注解 ↓ 2. 构建 Advisor通知器 ↓ 3. 创建代理工厂ProxyFactory ↓ 4. 选择代理策略JDK/CGLIB ↓ 5. 生成代理对象 ↓ 6. 方法调用时执行拦截链4.2 源码级执行流程4.2.1 代理对象的创建过程java// AbstractAutoProxyCreator 是关键类 public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { Override public Object postProcessAfterInitialization(Nullable Object bean, String beanName) { if (bean ! null) { Object cacheKey getCacheKey(bean.getClass(), beanName); // 判断是否需要创建代理 if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 1. 如果已经是代理对象或不需要代理直接返回 if (StringUtils.hasLength(beanName) this.targetSourcedBeans.contains(beanName)) { return bean; } // 2. 检查是否需要跳过 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 3. 判断是否是基础类或需要跳过的类 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // 4. 获取适用的通知器Advisor Object[] specificInterceptors getAdvicesAndAdvisorsForBean( bean.getClass(), beanName, null); // 5. 如果有适用的通知器则创建代理 if (specificInterceptors ! DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } }4.2.2 方法调用拦截过程java// JdkDynamicAopProxy 的 invoke 方法 public class JdkDynamicAopProxy implements AopProxy, InvocationHandler { Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy null; boolean setProxyContext false; TargetSource targetSource this.advised.targetSource; Object target null; try { // 1. 检查是否是 equals、hashCode 等方法 if (!this.equalsDefined AopUtils.isEqualsMethod(method)) { return equals(args[0]); } if (!this.hashCodeDefined AopUtils.isHashCodeMethod(method)) { return hashCode(); } if (!this.advised.opaque method.getDeclaringClass().isInterface() method.getDeclaringClass().isAssignableFrom(Advised.class)) { return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; // 2. 如果设置了 exposeProxy将当前代理暴露到 ThreadLocal if (this.advised.exposeProxy) { oldProxy AopContext.setCurrentProxy(proxy); setProxyContext true; } target targetSource.getTarget(); Class? targetClass (target ! null ? target.getClass() : null); // 3. 获取拦截器链 ListObject chain this.advised.getInterceptorsAndDynamicInterceptionAdvice( method, targetClass); // 4. 如果没有拦截器直接执行原方法 if (chain.isEmpty()) { Object[] argsToUse AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // 5. 创建方法调用对象并执行拦截器链 invocation new ReflectiveMethodInvocation( proxy, target, method, args, targetClass, chain); retVal invocation.proceed(); } // 6. 处理返回值 Class? returnType method.getReturnType(); if (retVal ! null retVal target returnType.isInstance(proxy) !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal proxy; } else if (retVal null returnType ! Void.TYPE returnType.isPrimitive()) { throw new AopInvocationException(Null return value from advice does not match primitive return type for: method); } return retVal; } finally { if (target ! null !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } } }4.3 拦截器链的执行java// ReflectiveMethodInvocation 的 proceed 方法 public class ReflectiveMethodInvocation implements ProxyMethodInvocation { private int currentInterceptorIndex -1; Override public Object proceed() throws Throwable { // 1. 如果所有拦截器都执行完毕执行原始方法 if (this.currentInterceptorIndex this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 2. 获取下一个拦截器 Object interceptorOrInterceptionAdvice this.interceptorsAndDynamicMethodMatchers.get(this.currentInterceptorIndex); // 3. 如果是动态方法匹配器先进行运行时检查 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // 不匹配时跳过当前拦截器 return proceed(); } } else { // 4. 执行拦截器 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } }五、Spring AOP 的切点表达式详解5.1 常用切点表达式javaAspect Component public class PointcutExamples { // 1. 方法执行切点 Pointcut(execution(public * com.example.service.*.*(..))) public void publicServiceMethods() {} // 2. 指定包下的所有方法 Pointcut(within(com.example.service..*)) public void inServiceLayer() {} // 3. 实现特定接口的类 Pointcut(this(com.example.service.UserService)) public void thisUserService() {} // 4. 目标对象类型 Pointcut(target(com.example.service.UserServiceImpl)) public void targetUserServiceImpl() {} // 5. 参数匹配 Pointcut(args(java.lang.String,..)) public void stringFirstParam() {} // 6. 注解匹配 Pointcut(annotation(com.example.annotation.Log)) public void logAnnotation() {} // 7. 带有特定注解的类 Pointcut(within(org.springframework.stereotype.Service)) public void serviceAnnotation() {} // 8. 带有特定注解的方法参数 Pointcut(args(com.example.annotation.Valid)) public void validArgsAnnotation() {} // 9. Bean 名称匹配 Pointcut(bean(userService)) public void userServiceBean() {} }5.2 切点表达式组合javaAspect Component public class CombinedPointcuts { // 组合切点AND、OR、NOT Pointcut(execution(* com.example.service.*.*(..)) within(com.example.service..*)) public void serviceLayerExecution() {} // 复杂的组合 Pointcut(execution(* com.example.service.*.*(..)) !execution(* com.example.service.*.get*(..))) public void serviceMethodsExceptGetters() {} }六、Spring AOP 的几种通知类型实现6.1 通知类型的实现原理java// 以环绕通知为例展示如何实现 public class AspectJAroundAdvice implements MethodInterceptor, Serializable { private final AspectJExpressionPointcut pointcut; private final transient Method aspectJAdviceMethod; private final AspectInstanceFactory aspectInstanceFactory; Override public Object invoke(MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException(MethodInvocation is not a Spring ProxyMethodInvocation: mi); } ProxyMethodInvocation pmi (ProxyMethodInvocation) mi; ProceedingJoinPoint pjp lazyGetProceedingJoinPoint(pmi); // 设置连接点信息 JoinPointMatch jpm getJoinPointMatch(pmi); // 通过反射调用通知方法 return invokeAdviceMethod( pjp, jpm, this.aspectInstanceFactory.getAspectInstance(), this.aspectJAdviceMethod); } }6.2 各种通知的执行时机text方法执行时间线 ┌─────────────────────────────────────────────────────────────┐ │ 方法调用过程 │ ├────────────┬────────┬────────┬────────┬────────┬────────────┤ │ │ │ │ │ │ │ │ Before │ 方法执行│ After │ After │ After │ Around │ │ Advice │ │ Advice │Returning│Throwing│ Advice │ │ │ │ │ Advice │ Advice │ │ └────────────┴────────┴────────┴────────┴────────┴────────────┘ ↑ ↑ ↑ ↑ ↑ 前置 方法体 后置 返回 异常 (总是执行)七、Spring AOP 的织入时机和方式7.1 织入时机编译时织入AspectJ在编译阶段织入需要特殊的编译器类加载时织入LTW在类加载到 JVM 时织入运行时织入Spring AOP在运行时通过动态代理织入7.2 Spring AOP 的织入过程java// 织入的核心过程 public class ProxyFactory extends ProxyCreatorSupport { public Object getProxy() { return createAopProxy().getProxy(); } protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } // 通过 AopProxyFactory 创建代理 return getAopProxyFactory().createAopProxy(this); } }八、Spring AOP 的局限性8.1 功能局限性只能拦截 public 方法无法拦截 final 方法无法拦截 static 方法无法拦截 private 方法只能作用于 Spring 容器管理的 Bean自调用问题同一个类中方法 A 调用方法 B方法 B 不会被拦截8.2 自调用问题的解决方案javaService public class UserService { public void methodA() { // 自调用methodB 不会被 AOP 拦截 methodB(); // 解决方案1注入自身代理 // userService.methodB(); } public void methodB() { // 业务逻辑 } } // 解决方案1通过 ApplicationContext 获取代理 Service public class UserServiceImpl implements UserService, ApplicationContextAware { private ApplicationContext context; Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context applicationContext; } public void methodA() { // 获取代理对象调用 UserService proxy context.getBean(UserService.class); proxy.methodB(); } } // 解决方案2使用 AspectJ 编译时织入解决根本问题九、Spring AOP 与 AspectJ 的区别9.1 对比表格特性Spring AOPAspectJ实现方式动态代理运行时字节码操作编译时/类加载时织入时机运行时编译时、类加载时性能相对较慢每次调用都有代理开销较快直接修改字节码功能仅支持方法级别的连接点支持字段、构造器等多种连接点使用复杂度简单集成在 Spring 中较复杂需要额外配置依赖仅需 Spring Core需要 AspectJ 编译器/织入器自调用支持不支持支持9.2 选择建议使用 Spring AOP 的场景仅需要方法拦截已经使用 Spring 框架不需要字段或构造器拦截可以接受轻微的性能损耗使用 AspectJ 的场景需要字段、构造器拦截需要最高性能需要解决自调用问题项目已经使用 AspectJ十、Spring AOP 性能优化10.1 优化策略javaConfiguration EnableAspectJAutoProxy( proxyTargetClass false, // 优先使用JDK动态代理 exposeProxy false // 不需要暴露代理时关闭 ) public class AopConfig { // 1. 精确的切点表达式减少匹配范围 Pointcut(execution(public * com.example.service.UserService.*(..))) public void userServiceMethods() {} // 2. 使用 within 减少运行时检查 Pointcut(within(org.springframework.stereotype.Service *)) public void serviceClasses() {} }10.2 性能最佳实践切点表达式优化避免使用execution(* *.*(..))这样的宽泛表达式优先使用within()而不是execution()合并多个切点表达式代理选择策略有接口的实现优先使用 JDK 动态代理CGLIB 创建代理较慢但调用较快缓存代理对象Spring 默认会缓存代理对象避免频繁创建和销毁代理对象十一、实际应用案例11.1 统一日志切面javaAspect Component Slf4j public class LoggingAspect { Pointcut(execution(* com.example.service.*.*(..)) || execution(* com.example.controller.*.*(..))) public void applicationLayer() {} Around(applicationLayer()) public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime System.currentTimeMillis(); String className joinPoint.getTarget().getClass().getSimpleName(); String methodName joinPoint.getSignature().getName(); Object[] args joinPoint.getArgs(); // 记录方法入参 log.info([{}#{}] 入参: {}, className, methodName, Arrays.toString(args)); try { Object result joinPoint.proceed(); long elapsedTime System.currentTimeMillis() - startTime; // 记录方法返回结果和执行时间 log.info([{}#{}] 返回: {}, 耗时: {}ms, className, methodName, result, elapsedTime); return result; } catch (Exception e) { log.error([{}#{}] 异常: {}, className, methodName, e.getMessage(), e); throw e; } } }11.2 事务管理切面javaAspect Component public class TransactionAspect { Autowired private PlatformTransactionManager transactionManager; Pointcut(annotation(com.example.annotation.Transactional)) public void transactionalMethod() {} Around(transactionalMethod()) public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable { TransactionStatus status transactionManager.getTransaction( new DefaultTransactionDefinition()); try { Object result joinPoint.proceed(); transactionManager.commit(status); return result; } catch (Exception e) { transactionManager.rollback(status); throw e; } } }11.3 缓存切面javaAspect Component public class CacheAspect { Autowired private CacheManager cacheManager; Pointcut(annotation(com.example.annotation.Cacheable)) public void cacheableMethod() {} Around(cacheableMethod()) public Object cacheAround(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature (MethodSignature) joinPoint.getSignature(); Method method signature.getMethod(); Cacheable cacheable method.getAnnotation(Cacheable.class); String cacheName cacheable.value(); Cache cache cacheManager.getCache(cacheName); // 生成缓存key String key generateKey(joinPoint); ValueWrapper valueWrapper cache.get(key); if (valueWrapper ! null) { return valueWrapper.get(); } Object result joinPoint.proceed(); cache.put(key, result); return result; } private String generateKey(ProceedingJoinPoint joinPoint) { // 生成缓存的key return joinPoint.getSignature().toLongString() Arrays.toString(joinPoint.getArgs()); } }十二、常见面试题深度解析12.1 经典面试题及答案Q1Spring AOP 和 AspectJ 有什么区别A1实现机制Spring AOP 使用动态代理运行时AspectJ 使用字节码操作编译时功能范围Spring AOP 仅支持方法级别AspectJ 支持字段、构造器、方法等性能AspectJ 性能更好编译时织入使用复杂度Spring AOP 更简单集成在 Spring 中Q2Spring AOP 是如何选择使用 JDK 动态代理还是 CGLIB 的A2如果目标对象实现了接口默认使用 JDK 动态代理如果目标对象没有实现接口使用 CGLIB可以通过配置强制使用 CGLIBEnableAspectJAutoProxy(proxyTargetClass true)Spring Boot 2.x 开始默认使用 CGLIBQ3Spring AOP 的自调用问题是什么如何解决A3问题同一个类中方法 A 调用方法 B方法 B 的 AOP 增强不会生效原因AOP 增强是通过代理对象实现的自调用时使用的是 this 引用不是代理对象解决方案使用AopContext.currentProxy()获取当前代理对象需要开启 expose-proxy使用 AspectJ 编译时织入将方法拆分到不同的类中Q4Spring AOP 中的切点表达式有哪些类型A4execution匹配方法执行within匹配类型声明this匹配代理对象类型target匹配目标对象类型args匹配参数类型annotation匹配带有指定注解的方法within匹配带有指定注解的类型target匹配目标对象带有指定注解args匹配参数带有指定注解bean匹配 Spring Bean 名称12.2 进阶面试题Q5Spring AOP 的拦截器链是如何执行的A5当代理对象的方法被调用时会触发invoke()方法获取适用于当前方法的拦截器链MethodInterceptor 列表创建MethodInvocation对象封装调用信息按顺序执行拦截器链每个拦截器可以决定是否继续执行链或直接返回最后一个拦截器执行后会调用原始方法然后逆序执行后置处理如果有Q6Spring AOP 是如何解决循环依赖问题的A6Spring 使用三级缓存解决循环依赖一级缓存单例对象缓存完整对象二级缓存早期曝光对象缓存尚未初始化的对象三级缓存对象工厂缓存ObjectFactoryAOP 代理对象的创建会提前进行当发生循环依赖时会先创建代理对象并放入缓存其他对象注入的是代理对象最终完成所有对象的初始化Q7如何实现一个自定义的 AOP 注解A7java// 1. 定义注解 Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface OperationLog { String value() default ; String operator() default system; } // 2. 实现切面 Aspect Component public class OperationLogAspect { Around(annotation(operationLog)) public Object logOperation(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable { // 获取注解信息 String operation operationLog.value(); String operator operationLog.operator(); // 记录操作日志 // ... return joinPoint.proceed(); } } // 3. 使用注解 Service public class UserService { OperationLog(value 创建用户, operator admin) public void createUser(User user) { // 业务逻辑 } }十三、Spring AOP 源码分析技巧13.1 关键源码位置代理创建AbstractAutoProxyCreator.wrapIfNecessary()DefaultAopProxyFactory.createAopProxy()JdkDynamicAopProxy/CglibAopProxy拦截器链执行ReflectiveMethodInvocation.proceed()MethodInterceptor.invoke()切点匹配AspectJExpressionPointcut.matches()MethodMatcher.matches()13.2 调试技巧设置断点位置JdkDynamicAopProxy.invoke()CglibAopProxy.intercept()AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean()观察代理对象java// 查看是否为代理对象 if (AopUtils.isAopProxy(bean)) { if (AopUtils.isJdkDynamicProxy(bean)) { System.out.println(JDK动态代理); } else if (AopUtils.isCglibProxy(bean)) { System.out.println(CGLIB代理); } }十四、Spring Boot 中的 AOP 自动配置14.1 自动配置原理java// Spring Boot 中的 AOP 自动配置类 Configuration ConditionalOnClass(EnableAspectJAutoProxy.class) ConditionalOnProperty(prefix spring.aop, name auto, havingValue true, matchIfMissing true) public class AopAutoConfiguration { Configuration EnableAspectJAutoProxy(proxyTargetClass false) ConditionalOnProperty(prefix spring.aop, name proxy-target-class, havingValue false, matchIfMissing false) public static class JdkDynamicAutoProxyConfiguration {} Configuration EnableAspectJAutoProxy(proxyTargetClass true) ConditionalOnProperty(prefix spring.aop, name proxy-target-class, havingValue true, matchIfMissing true) public static class CglibAutoProxyConfiguration {} }14.2 常用配置属性yamlspring: aop: auto: true # 是否开启AOP自动代理 proxy-target-class: true # 是否使用CGLIB代理默认true # 或者在 application.properties 中 # spring.aop.autotrue # spring.aop.proxy-target-classtrue十五、AOP 最佳实践和常见陷阱15.1 最佳实践切面设计原则单一职责一个切面只做一件事关注点分离业务逻辑和横切关注点分离避免过度使用不是所有功能都适合用 AOP性能考虑避免在切面中执行耗时操作使用精确的切点表达式考虑缓存代理对象可维护性为切面编写单元测试文档化切面的作用和范围监控切面的执行情况15.2 常见陷阱切点表达式过于宽泛java// 错误示例匹配所有方法性能差 Pointcut(execution(* *.*(..))) // 正确示例精确匹配 Pointcut(execution(public * com.example.service.*.*(..)))切面顺序问题java// 使用 Order 注解指定切面执行顺序 Aspect Component Order(1) // 数字越小优先级越高 public class LoggingAspect {} Aspect Component Order(2) public class TransactionAspect {}异常处理不当javaAround(serviceLayer()) public Object handleException(ProceedingJoinPoint joinPoint) { try { return joinPoint.proceed(); } catch (Exception e) { // 不要吞掉异常除非确定要处理 log.error(方法执行异常, e); throw e; // 重新抛出异常 } }总结Spring AOP 作为 Spring 框架的核心模块之一提供了强大的面向切面编程能力。通过本文的详细解析我们应该掌握核心概念切面、连接点、切点、通知等基本概念实现原理JDK 动态代理和 CGLIB 动态代理的工作原理工作流程从代理创建到方法拦截的完整流程使用技巧切点表达式、各种通知类型的使用高级特性切面顺序、自调用问题、性能优化等实际应用日志、事务、缓存等常见场景的实现源码理解关键源码位置和调试技巧