首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【SpringBoot】Spring AOP 原理 && 静态代理 && 动态代理

【SpringBoot】Spring AOP 原理 && 静态代理 && 动态代理

原创
作者头像
lirendada
发布2026-08-06 11:30:18
发布2026-08-06 11:30:18
910
举报
文章被收录于专栏:JavaJava

Spring AOP 原理

一、代理模式

定义:通过一个代理对象控制对目标对象的访问,并在不修改目标类的前提下,对其功能进行增强或控制

生活中的代理

  • 艺人经纪人:广告商找艺人拍广告,需要经过经纪人,由经纪人来和艺人进行沟通
  • 房屋中介:房屋进行租赁时,卖方会把房屋授权给中介,由中介来代理看房,房屋咨询等服务
  • 经销商:厂商不直接对外销售产品,由经销商负责代理销售
  • 秘书/助理:合作伙伴找老板谈合作,需要先经过秘书/助理预约

代理模式的主要角色

  1. Subject:业务接口类。可以是抽象类或者接口
  2. RealSubject:业务实现类。具体的业务执行,也就是被代理对象
  3. Proxy:代理类。RealSubject的代理

比如房屋租赁: Subject:就是提前定义了房东做的事情,交给中介代理,也是中介要做的事情 RealSubject:房东 Proxy:中介

根据代理的创建时期,代理模式分为静态代理和动态代理。

  • 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
  • 动态代理:在程序运行时,运用反射机制动态创建而成。

1. 静态代理

静态代理:在程序运行前,代理类的 .class 文件就已经存在了。

即在出租房子之前,中介已经做好了相关的工作,就等租户来租房子了

  1. 定义接口(定义房东要做的事情,也是中介需要做的事情)
    代码语言:javascript
    复制
    public interface HouseSubject {
        void rentHouse();
    }

2. 实现接口(房东出租房子)

代码语言:javascript
复制
public class RealHouseSubject implements HouseSubject{
    @Override
    public void rentHouse() {
        System.out.println("我是房东, 我出租房子");
    }
}

3. 代理(中介,帮房东出租房子)

代码语言:javascript
复制
public class HouseProxy implements HouseSubject{
    // 将被代理对象声明为成员变量
    private HouseSubject houseSubject;
    
    public HouseProxy(HouseSubject houseSubject) {
        this.houseSubject = houseSubject;
    }
    
    @Override
    public void rentHouse() {
        //开始代理
        System.out.println("我是中介, 开始代理");
        //代理房东出租房子
        houseSubject.rentHouse();
        //代理结束
        System.out.println("我是中介, 代理结束");
    }
}

4. 使用

代码语言:javascript
复制
public class StaticMain {
    public static void main(String[] args) {
        HouseSubject subject = new RealHouseSubject();
        // 创建代理类
        HouseProxy proxy = new HouseProxy(subject);
        // 通过代理类访问目标方法
        proxy.rentHouse();
    }
}

运行结果:

上面这个代理实现方式就是静态代理。

从上述程序可以看出,虽然静态代理也完成了对目标对象的代理,但是由于代码都写死了,对目标对象的每个方法的增强都是手动完成的,非常不灵活,所以日常开发几乎看不到静态代理的场景。

2. 动态代理

相比于静态代理来说,动态代理更加灵活。

我们不需要针对每个目标对象都单独创建一个代理对象,而是把这个创建代理对象的工作推迟到程序运行时由 JVM 来实现。

也就是说动态代理在程序运行时,根据需要动态创建生成

比如房屋中介,我不需要提前预测都有哪些业务,而是业务来了我再根据情况创建。

Java 对动态代理进行了实现,并给我们提供了一些 API,常见的实现方式有两种:

  1. JDK动态代理
  2. CGLIB动态代理

① JDK 动态代理

实现步骤:

  1. 定义一个接口及其实现类。
  2. 自定义 InvocationHandler 并重写 invoke 方法,在 invoke 方法中我们会调用目标方法(被代理类的方法)并自定义一些处理逻辑。
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象

实现 InvocationHandler 接口:

代码语言:javascript
复制
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class JDKInvocationHandler implements InvocationHandler {
    // 目标对象即就是被代理对象(也就是房东)
    private Object target;
    
    public JDKInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 执行代理的事情
        System.out.println("我是中介, 开始代理");
        
        // 执行房东的事情
        Object retVal = method.invoke(target, args);
        
        // 执行代理的事情
        System.out.println("我是中介, 代理结束");
        return retVal;
    }
}

创建一个代理对象并使用:

代码语言:javascript
复制
public class DynamicMain {
    public static void main(String[] args) {
        HouseSubject target= new RealHouseSubject(); // 创建房东(得实现接口才行)
        
        // 创建一个代理类:通过被代理类、被代理实现的接口、方法调用处理器来创建
        HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(
            target.getClass().getClassLoader(), // 类加载器
            new Class[]{HouseSubject.class},    // 代理要实现的接口
            new JDKInvocationHandler(target)    // 调用处理器
        );
        proxy.rentHouse();
    }
}

顺序解析:

  1. 业务层调用 proxy.rentHouse()
  2. JVM 调用动态生成的代理类 $Proxy...
  3. 代理类把方法调用委托给 invoke()
  4. invoke() 中:
    1. 前置逻辑(中介的事)
    2. 调用 method.invoke(target, args) 执行房东的真实方法
    3. 后置逻辑(中介的事)
  5. 返回结果给业务层

注意事项:

  1. JDK 动态代理必须有接口
    1. 如果 RealHouseSubject 没有实现 HouseSubject,会报错 IllegalArgumentException
  2. 代理对象类型

HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(...);

  • 返回类型是接口类型,不是目标类
  • 不能直接强转成 RealHouseSubject

3. 每次方法调用都会经过 invoke()

  1. 前置、后置、环绕逻辑全部在这里
  2. 适合做 事务、日志、权限、缓存等横切逻辑

4. 性能问题

  1. JDK 动态代理内部用反射调用 method.invoke(),有一点性能开销
  2. 如果没有接口,Spring 会选择 CGLIB 代理

② CGLIB 动态代理

JDK 动态代理有一个最致命的问题是只能代理实现了接口的类。 有些场景下,我们的业务代码是直接实现的,并没有接口定义。为了解决这个问题,可以用 CGLIB 动态代理机制来解决。

CGLIB(Code Generation Library)是一个基于 ASM 的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理,很多知名的开源框架都使用到了 CGLIB。例如 Spring 中 AOP 模块:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理

注意:需要添加依赖 和 JDK 动态代理不同,CGLIB 实际是属于一个开源项目,如果你要使用它的话,需要手动添加相关依赖。 <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>

实现步骤:

  1. 定义一个类(被代理类,即房东)
  2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于增强目标方法,和 JDK 动态代理中的 invoke 方法类似
  3. 通过 Enhancer 类的 create() 创建代理类
代码语言:javascript
复制
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

// 1. 目标类
class RealHouseSubject {
    public void rentHouse() {
        System.out.println("房东租房子");
    }
}

// 2. 代理拦截器
class CGLIBInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("我是中介, 开始代理");

        // 执行父类方法(目标方法)
        Object retVal = methodProxy.invokeSuper(o, args);

        System.out.println("我是中介, 代理结束");
        return retVal;
    }
}

// 3. 测试
public class DynamicMain {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealHouseSubject.class);  // 继承目标类
        enhancer.setCallback(new CGLIBInterceptor());    // 设置拦截器
        RealHouseSubject proxy = (RealHouseSubject) enhancer.create();

        proxy.rentHouse();
    }
}
两者区别

特性

JDK 动态代理

CGLIB

接口

必须

不需要

继承

通过继承目标类

方法限制

无 final 限制

不能代理 final 方法

生成代理

Runtime Proxy Class

子类继承生成

Spring 默认

优先

仅无接口或 proxy-target-class=true

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • Spring AOP 原理
    • 一、代理模式
      • 1. 静态代理
      • 2. 动态代理
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档