Skip to content

动态代理与 AOP 原理

一、静态代理 vs 动态代理

┌─────────────────────────────────────────────────────────────────┐
│                    静态代理 vs 动态代理                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  静态代理:                                                     │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐       │
│  │   Client    │────▶│ ProxyUser   │────▶│ RealUser    │       │
│  │             │     │  Service    │     │  Service    │       │
│  └─────────────┘     └─────────────┘     └─────────────┘       │
│                                                                  │
│  问题:每个类都要写一个代理类                                     │
│                                                                  │
│  动态代理:                                                     │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐       │
│  │   Client    │────▶│   Proxy    │────▶│ RealUser    │       │
│  │             │     │  Generator  │     │  Service    │       │
│  └─────────────┘     └─────────────┘     └─────────────┘       │
│                              │                                   │
│                        运行时代理生成                              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

二、JDK 动态代理

实现原理

java
public class JDKProxy implements InvocationHandler {
    
    private Object target;  // 被代理对象
    
    public JDKProxy(Object target) {
        this.target = target;
    }
    
    // 创建代理对象
    public Object createProxy() {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),   // 类加载器
            target.getClass().getInterfaces(),    // 接口列表
            this                                    // InvocationHandler
        );
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强
        System.out.println("before: " + method.getName());
        
        // 调用目标方法
        Object result = method.invoke(target, args);
        
        // 后置增强
        System.out.println("after: " + method.getName());
        
        return result;
    }
}

使用示例

java
public class UserServiceImpl implements UserService {
    @Override
    public void save(User user) {
        System.out.println("save user");
    }
}

// 创建代理
UserService proxy = (UserService) new JDKProxy(new UserServiceImpl()).createProxy();
proxy.save(user);  // 通过代理调用

三、CGLIB 字节码代理

实现原理

┌─────────────────────────────────────────────────────────────────┐
│                      CGLIB 代理原理                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  被代理类:                                                     │
│  public class UserService {                                     │
│      public void save() { }                                     │
│  }                                                              │
│                                                                  │
│  CGLIB 动态生成的子类:                                          │
│  public class UserService$$CGLIB extends UserService {          │
│      private MethodInterceptor callback;                         │
│                                                                  │
│      @Override                                                  │
│      public void save() {                                       │
│          callback.intercept(this, save method, null, null);    │
│      }                                                          │
│  }                                                              │
│                                                                  │
│  intercept 方法中可以:                                         │
│  - 前置增强                                                    │
│  - 调用父类方法(被代理方法)                                    │
│  - 后置增强                                                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

使用示例

java
public class CglibProxy implements MethodInterceptor {
    
    private Object target;
    
    public CglibProxy(Object target) {
        this.target = target;
    }
    
    public Object createProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, 
                          Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("before: " + method.getName());
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("after: " + method.getName());
        return result;
    }
}

四、JDK vs CGLIB

┌─────────────────────────────────────────────────────────────────┐
│                    JDK 动态代理 vs CGLIB                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────────────────┬──────────────────────────┐         │
│  │         JDK 动态代理       │         CGLIB          │         │
│  ├──────────────────────────┼──────────────────────────┤         │
│  │  基于接口                 │ 基于继承                │         │
│  │  被代理类必须实现接口      │ 被代理类可以无接口      │         │
│  │  Proxy.newProxyInstance   │ Enhancer.create()      │         │
│  │  反射调用                 │ 字节码生成,效率更高    │         │
│  │  InvocationHandler        │ MethodInterceptor       │         │
│  └──────────────────────────┴──────────────────────────┘         │
│                                                                  │
│  Spring 选择策略:                                               │
│  - 目标类有接口 → JDK 动态代理                                  │
│  - 目标类无接口 → CGLIB                                          │
│  - 强制使用 CGLIB → @EnableAspectJAutoProxy(proxyTargetClass=true)
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

五、Spring AOP 原理

代理创建时机

┌─────────────────────────────────────────────────────────────────┐
│                    Spring AOP 代理创建流程                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Bean 实例化完成后                                              │
│         │                                                       │
│         ▼                                                       │
│  BeanPostProcessor.postProcessAfterInitialization()              │
│         │                                                       │
│         ├─ AnnotationAwareAspectJAutoProxyCreator                │
│         │                                                       │
│         ├── 1. 检查是否需要代理                                  │
│         │    - 有 @Aspect 切面?                                 │
│         │    - 切点匹配当前 Bean?                               │
│         │                                                       │
│         ├── 2. 选择代理方式                                      │
│         │    - 有接口 → JDK 动态代理                            │
│         │    - 无接口 → CGLIB                                  │
│         │                                                       │
│         └── 3. 创建代理对象                                      │
│              返回代理对象替换原始 Bean                           │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

核心组件

1. AspectJExpressionPointcut        → 切点表达式解析
2. AspectJAdvisorFactory             → 从 @Aspect 类创建 Advisor
3. AnnotationAwareAspectJAutoProxyCreator → 创建 AOP 代理
4. JdkDynamicAopProxy / CglibAopProxy → 实际代理类

六、事务代理原理

┌─────────────────────────────────────────────────────────────────┐
│                    声明式事务原理                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  @Transactional                                                │
│         │                                                       │
│         ▼                                                       │
│  TransactionInterceptor(MethodInterceptor)                    │
│         │                                                       │
│         ├── 1. 检查是否开启事务                                  │
│         │                                                       │
│         ├── 2. 获取/创建事务                                    │
│         │    TransactionManager.getTransaction()                 │
│         │                                                       │
│         ├── 3. 调用目标方法                                      │
│         │                                                       │
│         ├── 4. 提交/回滚                                         │
│         │    commit() / rollback()                              │
│         │                                                       │
│         └── 5. 异常处理                                          │
│              rollbackFor 配置的异常 → 回滚                        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

七、面试高频问题

Q1: JDK 和 CGLIB 区别?

  • JDK:基于接口,Proxy.newProxyInstance
  • CGLIB:基于继承,Enhancer.create,效率更高

Q2: Spring 为什么默认用 JDK 代理?

  • JDK 是标准 API,无需引入第三方库
  • 如果目标类没有接口,Spring 才使用 CGLIB

Q3: AOP 代理调用流程?

  1. 客户端调用代理对象
  2. 代理对象调用 JdkDynamicAopProxy.invoke()
  3. 获取匹配的增强器链
  4. 依次执行各增强器的 before 方法
  5. 调用目标方法
  6. 依次执行各增强器的 after 方法

Q4: 代理对象方法调用目标对象?

通过 method.invoke(target, args) 调用

八、下一章预告

下一章我们将学习 事务传播行为

  • 7 种传播行为详解
  • 嵌套事务与 savepoint
  • 常见问题与解决方案

基于 MIT 许可发布