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 框架的核心技术之一。


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

相关推荐
你的人类朋友1 天前
说说签名与验签
后端
databook1 天前
Manim实现脉冲闪烁特效
后端·python·动效
RainbowSea1 天前
12. LangChain4j + 向量数据库操作详细说明
java·langchain·ai编程
RainbowSea1 天前
11. LangChain4j + Tools(Function Calling)的使用详细说明
java·langchain·ai编程
canonical_entropy1 天前
AI时代,我们还需要低代码吗?—— 一场关于模型、演化与软件未来的深度问答
后端·低代码·aigc
颜如玉1 天前
HikariCP:Dead code elimination优化
后端·性能优化·源码
考虑考虑1 天前
Jpa使用union all
java·spring boot·后端
用户3721574261351 天前
Java 实现 Excel 与 TXT 文本高效互转
java
bobz9651 天前
virtio vs vfio
后端
浮游本尊1 天前
Java学习第22天 - 云原生与容器化
java