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

Spring 动态代理详解

Spring 动态代理是框架底层的核心机制之一。它利用 JDK 的 Proxy 类和 InvocationHandler 接口,在运行时动态生成代理类,而非编译期硬编码。这种方式允许在不修改原有业务代码的前提下,统一添加日志、事务等横切关注点。相比静态代理,动态代理减少了重复代码,提升了扩展性和维护效率,是理解 Spring AOP 的基础。

星河入梦发布于 2025/2/5更新于 2026/10/2589 浏览
Spring 动态代理详解

什么是动态代理

先聊聊动态代理的概念,以及它和静态代理到底有什么不同。虽然两者在角色属性上相似,但代理类的实现方式截然不同。静态代理是我们提前写好代理类,而动态代理的代理类是在运行时动态生成的。

理解代理模式,得先搞清楚几个关键角色:

  • 抽象角色:通常由接口或抽象类定义。
  • 真实角色:被代理的实际对象。
  • 真实角色:被代理的实际对象。
  • 代理角色:负责代理真实角色,并在前后执行附属操作。
  • 客户:访问代理对象的调用方。

动态代理的分类

常见的实现方式主要有三类:

  1. 基于接口的动态代理:JDK 原生支持。
  2. 基于类的动态代理:如 CGLIB。
  3. 字节码实现:如 Javassist。

这里我们聚焦于 JDK 原生提供的动态代理机制,这也是 Spring AOP 默认使用的方案。

JDK 动态代理核心组件

要玩转 JDK 动态代理,主要涉及两个核心部分:

Proxy 类

这是动态代理类的超类,提供了创建代理实例的静态方法。所有的动态代理类都继承自它。

InvocationHandler 接口

这是代理实例的调用处理程序接口。当你调用代理对象的方法时,实际会触发这个接口中的 invoke 方法。

实战演示

为了更直观地理解,我们来看一个完整的 Demo 流程。

1. 定义接口与实现

首先需要一个业务接口和对应的实现类。注意命名规范,避免拼写错误。

package com.example.demo;

public interface UserService {
    void add();
    void delete(); // 修正了原文 delate 拼写
    void update();
    void query();
}
package com.example.demo;

public class UserServiceImpl implements UserService {
    
       {
        System.out.println();
    }

    
       {
        System.out.println();
    }

    
       {
        System.out.println();
    }

    
       {
        System.out.println();
    }
}
@Override
public
void
add
()
"增加了一名用户"
@Override
public
void
delete
()
"删除了一名用户"
@Override
public
void
update
()
"修改了一名用户"
@Override
public
void
query
()
"查找用户"

2. 编写调用处理器

这是最关键的一步。我们需要实现 InvocationHandler 接口,在这里决定代理对象被调用时具体做什么。

package com.example.demo.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {

    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    // 生成代理对象
    public Object getProxy() {
        return Proxy.newProxyInstance(
            this.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            this
        );
    }

    // 拦截方法调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置处理:比如记录日志
        System.out.println("执行了 " + method.getName() + " 方法");
        
        // 核心逻辑:反射调用真实对象的方法
        Object result = method.invoke(target, args);
        
        // 后置处理
        return result;
    }
}

这里有个细节要注意:invoke 方法里的 method.invoke(target, args) 才是真正执行业务逻辑的地方。我们在它前后加入的逻辑,就是所谓的'横切关注点'。

3. 客户端调用

最后,客户端只需要持有代理对象,就像使用普通对象一样。

package com.example.demo.client;

import com.example.demo.UserService;
import com.example.demo.UserServiceImpl;
import com.example.demo.proxy.ProxyInvocationHandler;

public class Client {
    public static void main(String[] args) {
        // 真实角色
        UserServiceImpl userService = new UserServiceImpl();

        // 创建代理处理器
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        handler.setTarget(userService);

        // 获取代理对象
        UserService proxy = (UserService) handler.getProxy();
        
        // 调用代理方法
        proxy.add();
    }
}

总结

与静态代理不同,在这个实例中我们没有手动创建具体的代理类,而是让动态代理机制在运行时自动生成。这意味着多个不同的真实角色可以复用同一个代理类,极大地提高了开发效率。这种灵活性正是 Spring 能够轻松实现 AOP 等功能的基础。

目录

  1. 什么是动态代理
  2. 动态代理的分类
  3. JDK 动态代理核心组件
  4. Proxy 类
  5. InvocationHandler 接口
  6. 实战演示
  7. 1. 定义接口与实现
  8. 2. 编写调用处理器
  9. 3. 客户端调用
  10. 总结

更多推荐文章

查看全部
  • ComfyUI 插件管理完全指南
  • 分布式任务调度:多数据库兼容的策略封装
  • Qwen3-VL WEBUI 性能对比:Instruct 与 Thinking 版本
  • Spring Cloud 商品服务实战:库存、缓存与分布式锁设计
  • LightGlue ONNX C++ 推理实践
  • 使用 Python 和 Twilio 实现每日自动发送天气短信
  • 百度发布国内首个产业级医疗大模型灵医
  • VSCode 中如何正确创建并推送 Git Tag:避坑指南与最佳实践
  • 华为 OD 机试:二维伞雨滴效应的 BST 验证与实现
  • 大语言模型在医疗领域的进展、应用与挑战
  • Coze 智能体开发指南:从配置到工作流实战
  • 云开发 Copilot:AI 赋能的低代码开发
  • Pyenv shell 命令临时切换 Python 版本
  • 扩散模型原理与图像生成实战
  • Python 爬虫技术详解:核心难点、学习路径与实战规范
  • Spring AI 实战:基于 SSE 构建 MCP Server 与 Client
  • Web 可访问性最佳实践:构建人人可用的前端界面
  • 使用 llama.cpp 在本地运行大模型:Mac 和 Linux 实操记录
  • MAC 地址简介及 Windows 系统查看方法
  • 操作系统进程状态核心逻辑与 Linux 实现

相关免费在线工具

  • 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