跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring AOP 的代理模式与动态代理:从原理到源码

Spring AOP 底层通过 JDK 与 CGLIB 动态代理实现无侵入增强。从静态代理演进到动态代理,再封装为切面、切点、通知等组件,开发者无需手动生成代理对象。源码中通过 ProxyFactory 根据目标类接口情况和配置自动选择代理类型。文章还对比了 AOP 与拦截器、统一异常器的适用场景,强调方法级增强应首选 AOP。

活在当下发布于 2026/6/14更新于 2026/10/1763 浏览
Spring AOP 的代理模式与动态代理:从原理到源码

代理模式速览

代理模式就是在调用方和目标对象之间加一个中间人,以便在不修改目标代码的前提下增加额外行为。以房屋租赁为例,房东只负责租房,中介可以带上带看、签合同这些活儿。

角色对应示例作用说明
SubjectHouseSubject 接口定义目标对象和代理的共同行为('租房')
RealSubjectRealHouseSubject(房东)目标对象,实际干活的人
ProxyHouseProxy(中介)代理类,包装目标对象,前后添加增强逻辑

静态代理:手工写代理类

静态代理需要提前写好代理类,一个代理对应一个接口。

// 公共接口
public interface HouseSubject {
    void rentHouse();
}

// 目标对象(房东)
public class RealHouseSubject implements HouseSubject {
    @Override
    public void rentHouse() {
        System.out.println("房东出租房屋");
    }
}

// 代理类(中介)
public class HouseProxy implements HouseSubject {
    private HouseSubject target;

    public HouseProxy(HouseSubject target) {
        this.target = target;
    }

    @Override
    public void rentHouse() {
        System.out.println("带看房");  // 前置增强
        target.rentHouse();
        System.out.println("签合同");  // 后置增强
    }
}

// 使用
HouseSubject agent = new HouseProxy(new RealHouseSubject());
agent.rentHouse();

静态代理的局限很明显:一个代理类只能服务于同一接口的目标。如果系统里有几十个需要增强的服务,就要写几十个代理类。所以动态代理才显得必要。

JDK 动态代理:给有接口的类生成代理

JDK 动态代理在运行时动态生成代理对象,核心是 InvocationHandler 和 Proxy。

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 result = method.invoke(target, args);
        System.out.println("代理结束");
        return result;
    }
}

// 调用方式
HouseSubject realLandlord = new RealHouseSubject();
HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(
        realLandlord.getClass().getClassLoader(),
        new Class[]{HouseSubject.class},
        new JDKInvocationHandler(realLandlord));
proxy.rentHouse();

newProxyInstance 需要三个参数:类加载器、接口数组、InvocationHandler 实例。它的缺点同样明确——只能代理实现了接口的类。

CGLIB 动态代理:没有接口也能代理

CGLIB 通过生成目标类的子类来实现增强,核心是 MethodInterceptor 和 Enhancer。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CGLIBInterceptor 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;
    }
}

// 使用
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealHouseSubject.class);
enhancer.setCallback(new CGLIBInterceptor());
RealHouseSubject proxy = (RealHouseSubject) enhancer.create();
proxy.rentHouse();

不需要任何接口,对于普通的 Java 类也能生成代理。

JDK 与 CGLIB 对比

维度JDK 动态代理CGLIB 动态代理
代理条件必须实现接口可以代理无接口的类
核心 APIInvocationHandler + ProxyMethodInterceptor + Enhancer
底层原理基于接口的动态代理基于子类的动态代理
Spring 中的场景优先用于有接口的 Bean兜底方案,或强制使用(如 Spring Boot 2.x 默认)

Spring AOP 如何封装动态代理

Spring AOP 把底层的动态代理细节封装成切面、切点和通知,你只需关注业务规则。

核心组件

  • 切面(@Aspect):带有 @Aspect 注解的类,交给 Spring 管理,内部包含增强逻辑。
  • 切点(@Pointcut 或 execution 表达式):指定哪些方法需要被增强。
  • 通知(@Before、@After、@Around 等):定义增强的具体时机和内容。

执行流程

调用被增强的方法时,实际调用的是 Spring 容器中的代理对象。代理对象按顺序执行相应通知(比如前置日志),再调用目标方法,最后再执行后置或返回通知。对业务代码完全透明。

Spring AOP 源码简析:代理生成

Spring 在 Bean 初始化后通过 AbstractAutoProxyCreator 的子类(例如 AnnotationAwareAspectJAutoProxyCreator)检查是否需要创建代理。核心方法 wrapIfNecessary 最终使用 ProxyFactory 生成代理。

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(targetBean);
// 如果强制使用 CGLIB,或者目标类没有接口,则采用 CGLIB
if (proxyTargetClass) {
    proxyFactory.setProxyTargetClass(true);
}
return proxyFactory.getProxy(classLoader);

getProxy 内部会根据条件创建 JdkDynamicAopProxy 或 CglibAopProxy。Spring Boot 2.x 开始,默认将 proxyTargetClass 设为 true,即优先使用 CGLIB。如果你希望改回 JDK 代理,可在配置文件中设置 spring.aop.proxy-target-class=false。

AOP 与拦截器、统一异常处理的分工

如果你的后端系统像一个餐厅,那么:

组件角色范围核心作用
拦截器大门保安HTTP 请求/响应校验 token、接口限流、记录请求日志
统一异常售后客服全局异常兜底@RestControllerAdvice + @ExceptionHandler 统一错误返回
AOP万能服务员任意方法层面事务管理、方法耗时统计、细粒度日志

什么时候该用 AOP?

  • 需要增强 Service 层、Mapper 层的方法——拦截器管不到这些地方。
  • 只需针对某些方法(比如带特定注解的方法)做处理,而不是整个 Controller。
  • 需要拿到方法参数、返回值等更丰富的上下文。

几个简单的使用原则:

  1. 管 HTTP 请求/响应 → 用拦截器。
  2. 统一异常格式 → 用 @ControllerAdvice。
  3. 方法级别的增强 → 用 AOP(切面 + 切点 + 通知)。

总结

Spring AOP 的底层就是动态代理,JDK 和 CGLIB 两种方式覆盖了有接口和无接口的类。Spring 把代理的创建和增强逻辑的织入封装成声明式的编程模型,你只需写切面规则,不用碰业务代码。理清它和拦截器、统一异常处理的边界,能让你的代码分层更清晰。

目录

  1. 代理模式速览
  2. 静态代理:手工写代理类
  3. JDK 动态代理:给有接口的类生成代理
  4. CGLIB 动态代理:没有接口也能代理
  5. JDK 与 CGLIB 对比
  6. Spring AOP 如何封装动态代理
  7. 核心组件
  8. 执行流程
  9. Spring AOP 源码简析:代理生成
  10. AOP 与拦截器、统一异常处理的分工
  11. 总结

更多推荐文章

查看全部
  • 几款支持万方平台的 AIGC 降重工具实测对比
  • Cursor 在 C/C++ 开发中的实战使用指南
  • 在 Linux 上把 OpenClaw 接到 QQ 机器人
  • AI 大模型时代:工程师与项目管理者的机遇与挑战
  • LangChain 使用知识库修复大模型幻觉问题
  • 基于 YOLO 标注格式的无人机航拍人员搜救检测数据集
  • 基于实际案例的 AI 大模型应用与提示词工程实践指南
  • Llama.cpp 跨平台部署实战:本地运行大模型完整指南
  • 转行 AI 产品经理:面试核心问题与准备指南
  • 本地部署 Wan2.1 视频生成模型及远程访问配置
  • RTX50 系列显卡与 CUDA、PyTorch、Python 版本对应关系
  • 字节跳动 AI 产品经理三轮面试经验与通用问题解析
  • LeetCode 3637. 三段式数组 I 解法:一次循环遍历
  • 基于 Nexent 知识库与 MCP 生态构建智能烹饪顾问实战
  • 编辑器 AI 工具实战:OpenClaw 与 Codex 深度指南
  • Java 核心:char、String、StringBuilder 与 StringBuffer 详解
  • Anthropic 调整服务区域限制,中国地区用户可能无法使用
  • Linux 网络层 IP 协议详解
  • Vitis AI 推理加速实战:从零实现 FPGA 部署
  • Kubernetes与AI推理服务最佳实践

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online