Spring AOP实现原理
AOP核心概念
核心概念解析
- Aspect(切面): 封装横切关注点的模块,包含多个 Advice 和 Pointcut,如日志切面、事务切面、权限校验切面。
 - Join Point(连接点):程序执行过程中的一个点(如方法调用、异常抛出),可插入切面逻辑的位置。
 - Advice(通知):在特定连接点执行的动作(如前置、后置、环绕处理),如记录方法执行时间、事务提交或回滚。
 - Pointcut(切点):通过表达式匹配一组连接点,定义哪些连接点会被切面处理。
 - Target Object(目标对象):被代理的原始对象(包含业务逻辑的 Bean)。
 - Proxy(代理):由 Spring 生成的代理对象,包装目标对象以插入切面逻辑。
 - Weaving(织入):将切面代码与目标对象关联的过程(编译时、类加载时或运行时)。
 
Advice(通知)类型
- @Before(前置通知):在目标方法执行前触发;适用于参数校验、权限控制。
 - @After(后置通知):在目标方法执行后触发(无论是否抛出异常),适用于资源清理(如关闭文件流)。
 - @AfterReturning(返回后通知):在目标方法 正常返回后 触发,可访问返回值。
 - @AfterThrowing(异常通知):在目标方法 抛出异常后 触发,可捕获特定异常类型。
 - @Around(环绕通知):包裹目标方法,控制其执行流程(类似过滤器),需手动调用 
proceed()执行目标方法。 
Pointcut(切点)表达式
| 表达式 | 说明 | 
|---|---|
execution(* com.example.service.*.*(..)) | 
匹配 com.example.service 包下所有类的所有方法 | 
@annotation(com.example.anno.Log) | 
匹配被 @Log 注解标记的方法 | 
within(com.example.service.UserService) | 
匹配 UserService 类中的所有方法 | 
args(java.lang.String) | 
匹配参数类型为 String 的方法 | 
代理机制
- JDK 动态代理
- 条件:目标对象实现了至少一个接口。
 - 原理:基于接口生成代理类,调用 
InvocationHandler.invoke()插入切面逻辑。 
 - CGLIB 动态代理
- 条件:目标对象未实现接口(或配置强制使用 CGLIB)。
 - 原理:通过继承目标类生成子类代理,覆盖父类方法。
 
 
AOP 与 AspectJ 的关系
| 维度 | Spring AOP | AspectJ | 
|---|---|---|
| 织入时机 | 运行时动态代理 | 编译时或类加载时(支持更丰富的连接点) | 
| 性能 | 略低(运行时生成代理) | 更高(编译时优化) | 
| 功能范围 | 仅支持方法级别的连接点 | 支持字段、构造器、静态代码块等连接点 | 
| 使用场景 | 轻量级应用,无需复杂切面 | 企业级复杂切面需求(如性能监控、安全检查) | 
JDK动态代理与CGLIB代理的底层实现
JDK 动态代理
- 
核心原理
- 
基于接口:要求目标对象必须实现至少一个接口。
 - 
反射机制:通过
java.lang.reflect.Proxy和InvocationHandler动态生成代理类。 - 
代理对象行为:代理类实现目标接口,并将方法调用转发到
InvocationHandler。 
 - 
 - 
实现步骤
- 
定义接口与实现类
public interface UserService { void saveUser(User user); } public class UserServiceImpl implements UserService { public void saveUser(User user) { /* 业务逻辑 */ } } - 
实现
InvocationHandlerpublic class JdkProxyHandler implements InvocationHandler { private Object target; // 目标对象 public JdkProxyHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置增强 System.out.println("Before method: " + method.getName()); // 调用目标方法 Object result = method.invoke(target, args); // 后置增强 System.out.println("After method: " + method.getName()); return result; } } - 
生成代理对象
UserService target = new UserServiceImpl(); UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), // 必须为接口数组 new JdkProxyHandler(target) ); proxy.saveUser(new User()); // 调用代理方法 
 - 
 - 
源码关键点
Proxy.newProxyInstance():动态生成代理类的字节码,其类名通常为$Proxy0、$Proxy1等。- 代理类结构:代理类继承 
Proxy并实现目标接口,所有方法调用均委托给InvocationHandler.invoke()。 
 
CGLIB 动态代理
- 
核心原理
- 
基于继承:通过生成目标类的子类作为代理类(即使目标类未实现接口)。
 - 
字节码操作:使用 ASM 库直接修改字节码,生成新类。
 - 
方法拦截:通过
MethodInterceptor接口实现方法增强。 
 - 
 - 
实现步骤
- 
定义目标类
public class UserService { public void saveUser(User user) { /* 业务逻辑 */ } } - 
实现
MethodInterceptorpublic class CglibMethodInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 前置增强 System.out.println("Before method: " + method.getName()); // 调用目标方法(通过 FastClass 机制,避免反射) Object result = proxy.invokeSuper(obj, args); // 后置增强 System.out.println("After method: " + method.getName()); return result; } } - 
生成代理对象
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); // 设置父类 enhancer.setCallback(new CglibMethodInterceptor()); UserService proxy = (UserService) enhancer.create(); // 生成代理对象 proxy.saveUser(new User()); // 调用代理方法 
 - 
 - 
源码关键点
- Enhancer 类:负责生成代理类的字节码。
 - FastClass 机制:为代理类和目标类生成索引,直接通过索引调用方法,避免反射(性能优于 JDK 代理)。
 - 代理类结构:代理类继承目标类,重写父类方法,并在方法中调用 
MethodInterceptor.intercept()。 
 
JDK 代理与 CGLIB 代理对比
| 维度 | JDK 动态代理 | CGLIB 动态代理 | 
|---|---|---|
| 代理方式 | 基于接口 | 基于继承 | 
| 目标类要求 | 必须实现接口 | 可为任意类(非 final) | 
| 性能 | 生成快,调用慢(反射) | 生成慢,调用快(FastClass) | 
| 方法覆盖 | 仅代理接口方法 | 代理所有非 final 方法 | 
| 依赖 | 内置 JDK 支持 | 需引入 CGLIB 库(Spring 已默认包含) | 
| 代理类名 | $Proxy0、$Proxy1 | 
UserService$$EnhancerByCGLIB$$12345678 | 
Spring AOP 的代理选择策略
- 默认行为:若目标类实现接口 → 使用 JDK 动态代理;若目标类未实现接口 → 使用 CGLIB 动态代理。
 - 强制使用 CGLIB:通过 
@EnableAspectJAutoProxy(proxyTargetClass = true)配置,强制对所有类使用 CGLIB。 - 排除 final 方法:CGLIB 无法代理 
final方法,需确保目标方法可被重写。 
代理对象的生成流程
核心类与接口
- ProxyFactory
- 作用:代理对象的配置工厂,用于设置目标对象、切面(Advisor)、通知(Advice)等。
 - 继承关系:
ProxyFactory→ProxyCreatorSupport→AdvisedSupport。 
 - AopProxy
- 接口:定义代理对象的生成方法 
getProxy()。 - JdkDynamicAopProxy:基于 JDK 动态代理实现。
 - ObjenesisCglibAopProxy:基于 CGLIB 动态代理实现(Spring 优化后的版本)。
 
 - 接口:定义代理对象的生成方法 
 - AdvisedSupport:封装代理配置信息(目标对象、切面列表、代理接口等),供 
AopProxy使用。 
代理生成流程
- 
配置阶段(ProxyFactory 初始化):开发者通过
ProxyFactory设置代理所需的元数据。// 1. 创建ProxyFactory并配置 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(new UserServiceImpl()); // 目标对象 proxyFactory.addAdvice(new LoggingAdvice()); // 添加通知(Advice) proxyFactory.setInterfaces(UserService.class); // 指定代理接口(可选) // 2. 生成代理对象 UserService proxy = (UserService) proxyFactory.getProxy(); - 
代理生成阶段(AopProxy 创建代理):选择代理策略(JDK或CGLIB)、创建AopProxy实例、生成代理对象。
 
通知(Advice)的执行链路
责任链模式的核心思想
- 定义:将多个处理器(拦截器)按顺序连接成链,每个处理器决定是否将请求传递给下一个处理器。
 - 优点:解耦处理器之间的依赖,支持动态扩展处理逻辑。
 - 在 Spring AOP 中的应用:将多个通知(如 
@Around)转换为拦截器(MethodInterceptor),形成链式结构,按顺序执行。 
拦截器链的构建
- 拦截器链的组成:每个 
Advisor(切面) 会被适配为一个MethodInterceptor(方法拦截器)。 - 链的构建过程:Spring 在创建代理对象时,将所有 
Advisor转换为MethodInterceptor,并按优先级排序,形成拦截器链。 
拦截器链执行流程
               +---------------------+
               | MethodInvocation    |
               | (ReflectiveMethod)  |
               +----------+----------+
                          | proceed()
                          v
+----------------+     +----------------+     +----------------+     +----------------+
| Interceptor 1  | --> | Interceptor 2  | --> | Interceptor 3  | --> | Target Method  |
| (@Before)      |     | (@Around)      |     | (@After)       |     |                |
+----------------+     +----------------+     +----------------+     +----------------+
AspectJ注解驱动的AOP解析过程
切面类的识别与注册
- @Aspect注解:标记一个类为切面。
 - @Component或@Bean:确保切面类被Spring容器管理。
 - AnnotationAwareAspectJAutoProxyCreator:继承自
AbstractAutoProxyCreator的后置处理器,负责初始化后生成Proxy。 
切点表达式解析与匹配
- AspectJExpressionPointcut:封装AspectJ切点表达式,实现
Pointcut接口的getClassFilter()和getMethodMatcher()。 - 表达式解析:使用AspectJ的
PointcutParser将字符串表达式转换为抽象语法树(AST)。 - 匹配逻辑:在运行时检查目标类和方法是否匹配切点表达式。
 
通知方法适配为Advice
| 注解 | Advice类型 | 适配器类 | 
|---|---|---|
| @Before | MethodBeforeAdvice | 
AspectJMethodBeforeAdvice | 
| @After | AfterAdvice | 
AspectJAfterAdvice | 
| @AfterReturning | AfterReturningAdvice | 
AspectJAfterReturningAdvice | 
| @AfterThrowing | ThrowsAdvice | 
AspectJAfterThrowingAdvice | 
| @Around | MethodInterceptor | 
AspectJAroundAdvice | 
构建Advisor并整合到代理
- 收集Advisor:在
AnnotationAwareAspectJAutoProxyCreator中,查找所有切面类的Advisor。 - 匹配目标Bean:判断当前Bean是否需要被代理(即是否存在匹配的Advisor)。
 - 生成代理对象:根据配置(JDK或CGLIB)生成代理对象,并将Advisor转换为拦截器链。
 
动态代理生成与拦截链执行
- 代理对象调用方法:代理对象拦截目标方法调用。
 - 构建拦截器链:所有匹配的
Advisor转换为MethodInterceptor,按优先级排序。 - 链式执行:通过
ReflectiveMethodInvocation递归调用拦截器,直至执行目标方法。 
                    
                
                
            
        
浙公网安备 33010602011771号