Java 动态代理详解:从原理到实战

Java 动态代理详解:从原理到实战

1. 什么是代理?

在软件开发中,代理模式(Proxy Pattern) 是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。

简单来说:代理就是帮别人做事的人

比如,你想买演唱会门票,可以自己去买(真实对象),也可以找黄牛帮你买(代理对象)。

在 Java 中,代理有两种:

  • 静态代理:代理类在编译期就已经生成。
  • 动态代理:代理类在运行时动态生成。

今天我们重点讲 动态代理


2. 为什么需要动态代理?

假设我们有一个接口 UserService,有多个方法,比如:

java 复制代码
public interface UserService {
    void createUser(String name);
    void deleteUser(String name);
}

如果我们想在每个方法执行前后加上 日志、权限验证 等功能,

静态代理需要手动写一个代理类,方法多了就很麻烦。

而动态代理可以让我们一次性编写通用逻辑,在运行时帮我们生成代理类,省时省力。


3. Java 动态代理的原理

Java 动态代理依赖 java.lang.reflect.Proxy 类和 InvocationHandler 接口。

核心思想:

  1. 接口:被代理的对象必须实现接口(JDK 动态代理的限制)。
  2. InvocationHandler:定义代理逻辑(方法调用前后做什么)。
  3. Proxy.newProxyInstance:运行时生成代理对象。

执行流程:

rust 复制代码
方法调用 -> 代理对象 -> InvocationHandler.invoke() -> 真实对象

4. 动态代理示例

4.1 接口与实现类

java 复制代码
public interface UserService {
    void createUser(String name);
    void deleteUser(String name);
}

public class UserServiceImpl implements UserService {
    @Override
    public void createUser(String name) {
        System.out.println("创建用户:" + name);
    }

    @Override
    public void deleteUser(String name) {
        System.out.println("删除用户:" + name);
    }
}

4.2 动态代理处理器

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class LoggingInvocationHandler implements InvocationHandler {
    private final Object target;

    public LoggingInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("[日志] 方法开始:" + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("[日志] 方法结束:" + method.getName());
        return result;
    }
}

4.3 创建代理对象

java 复制代码
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();

        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new LoggingInvocationHandler(target)
        );

        proxy.createUser("Alice");
        proxy.deleteUser("Bob");
    }
}

运行结果:

css 复制代码
[日志] 方法开始:createUser
创建用户:Alice
[日志] 方法结束:createUser
[日志] 方法开始:deleteUser
删除用户:Bob
[日志] 方法结束:deleteUser

classDiagram class UserService { <> +createUser(String name) +deleteUser(String name) } class UserServiceImpl { +createUser(String name) +deleteUser(String name) } class LoggingInvocationHandler { -Object target +invoke(Object proxy, Method method, Object[] args) Object } class Proxy { +newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) Object } class InvocationHandler { <> +invoke(Object proxy, Method method, Object[] args) Object } UserService <|.. UserServiceImpl InvocationHandler <|.. LoggingInvocationHandler Proxy --> InvocationHandler Proxy --> UserService LoggingInvocationHandler --> UserService

5. 动态代理的优缺点

优点:

  • 通用性强:一套代理逻辑可以应用到多个类。
  • 解耦:业务代码与横切逻辑(如日志、事务)分离。
  • 运行时生成:无需手动编写代理类。

缺点:

  • 只能代理接口(JDK 动态代理的限制)。
  • 反射调用有一定性能损耗(一般可忽略)。

6. 扩展:CGLIB 动态代理

如果目标类没有实现接口 ,JDK 动态代理就无能为力,这时可以用 CGLIB (基于继承生成子类代理)。

Spring AOP 就是根据情况选择 JDK 动态代理或 CGLIB。


7. 总结

Java 动态代理本质上是 在运行时生成代理类,通过反射调用目标对象的方法 ,并在调用前后插入额外逻辑。

它是实现 AOP(面向切面编程) 的重要基础,也是 Spring 框架的核心技术之一。


💡 建议:如果你在项目中需要对多个类的方法统一添加日志、权限、事务等功能,可以优先考虑动态代理,而不是在每个方法里手动写重复代码。

相关推荐
还不秃顶的计科生6 分钟前
多模态模型下载
java·linux·前端
程序员小崔日记8 分钟前
第30篇文章:一个大三计科生的自白
java·代码人生·claudecode
沛沛rh4513 分钟前
用 Rust 实现用户态调试器:mini-debugger项目原理剖析与工程复盘
开发语言·c++·后端·架构·rust·系统架构
范什么特西19 分钟前
解决idea未指定jdk问题webapp未被识别问题
java·开发语言·intellij-idea
是宇写的啊22 分钟前
SpringBoot日志
java·spring boot·spring
消失的旧时光-194333 分钟前
Spring Boot + MyBatis 从 0 到 1 跑通查询接口(含全部踩坑)
spring boot·后端·spring·mybatis
摇滚侠40 分钟前
Redis 和 MySQL 数据同步方案,ElasticSearch 和 MySQL 数据同步方案
java·redis·mysql
Rsun045511 小时前
IDEA隐藏无关文件
java·elasticsearch·intellij-idea
人道领域1 小时前
【黑马点评日记03】实战:Redis缓存穿透,缓存击穿,缓存雪崩全解析
java·开发语言·jvm·redis·spring·tomcat
SamDeepThinking1 小时前
Spring AOP记录日志,生产环境的代码长什么样
java·后端·架构