如何在Java中理解动态代理和静态代理

来源:中国站长站作者:关中王头衔:草根站长
导读:本期聚焦于小伙伴创作的《如何在Java中理解动态代理和静态代理》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何在Java中理解动态代理和静态代理》有用,将其分享出去将是对创作者最好的鼓励。

Java中的代理模式属于结构型设计模式,核心思想是在不修改目标对象代码的前提下,通过代理对象对目标对象的功能进行增强或者控制访问。根据代理类的生成时机不同,代理模式可以分为静态代理和动态代理两大类,下面分别介绍两者的实现方式和特点。

如何在Java中理解动态代理和静态代理

静态代理的实现

静态代理的代理类是在代码编写阶段就手动创建好的,代理类和目标类需要实现相同的接口,代理类内部持有目标类的实例,在调用目标方法前后可以添加增强逻辑。

静态代理示例

首先定义一个公共的接口,目标类和代理类都实现这个接口:

// 定义业务接口
public interface UserService {
    void addUser(String username);
}

// 目标类,实现业务接口
public class UserServiceImpl implements UserService {
    @Override
    public void addUser(String username) {
        System.out.println("添加用户:" + username);
    }
}

// 静态代理类,同样实现业务接口
public class UserServiceStaticProxy implements UserService {
    // 持有目标对象的实例
    private UserService target;

    public UserServiceStaticProxy(UserService target) {
        this.target = target;
    }

    @Override
    public void addUser(String username) {
        System.out.println("静态代理:方法执行前,记录日志");
        // 调用目标对象的方法
        target.addUser(username);
        System.out.println("静态代理:方法执行后,记录日志");
    }
}

测试静态代理的使用:

public class StaticProxyTest {
    public static void main(String[] args) {
        // 创建目标对象
        UserService target = new UserServiceImpl();
        // 创建静态代理对象
        UserService proxy = new UserServiceStaticProxy(target);
        // 调用代理对象的方法
        proxy.addUser("张三");
    }
}

静态代理的优点是逻辑简单,容易理解,缺点也很明显:如果需要代理的接口很多,或者接口的方法很多,就需要编写大量的代理类,代码冗余度高,维护成本大。

动态代理的实现

动态代理的代理类是在程序运行期间动态生成的,不需要手动编写代理类的代码。Java中常见的动态代理实现有两种:JDK动态代理和CGLIB动态代理。

JDK动态代理

JDK动态代理是Java原生支持的动态代理方式,要求目标类必须实现接口,代理对象会实现和目标类相同的接口。核心是通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现。

JDK动态代理示例,复用上面的UserServiceUserServiceImpl

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

// 实现InvocationHandler接口,定义代理逻辑
public class JdkDynamicProxyHandler implements InvocationHandler {
    // 持有目标对象
    private Object target;

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

    // 生成代理对象的方法
    public Object getProxyInstance() {
        // 使用Proxy.newProxyInstance生成代理对象
        // 第一个参数是目标类的类加载器
        // 第二个参数是目标类实现的接口数组
        // 第三个参数是当前InvocationHandler实例
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this
        );
    }

    // 代理对象调用方法时会执行这个方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK动态代理:方法执行前,记录日志");
        // 调用目标对象的方法
        Object result = method.invoke(target, args);
        System.out.println("JDK动态代理:方法执行后,记录日志");
        return result;
    }
}

测试JDK动态代理的使用:

public class JdkDynamicProxyTest {
    public static void main(String[] args) {
        // 创建目标对象
        UserService target = new UserServiceImpl();
        // 创建InvocationHandler实例
        JdkDynamicProxyHandler handler = new JdkDynamicProxyHandler(target);
        // 获取代理对象
        UserService proxy = (UserService) handler.getProxyInstance();
        // 调用代理对象的方法
        proxy.addUser("李四");
    }
}

CGLIB动态代理

CGLIB动态代理是基于ASM字节码框架实现的,不需要目标类实现接口,它通过生成目标类的子类作为代理类。CGLIB是第三方库,需要额外引入依赖,核心是通过net.sf.cglib.proxy.Enhancernet.sf.cglib.proxy.MethodInterceptor接口来实现。

CGLIB动态代理示例,目标类不需要实现接口:

// 目标类,不需要实现接口
public class OrderService {
    public void createOrder(String orderId) {
        System.out.println("创建订单:" + orderId);
    }
}

实现CGLIB的代理逻辑:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

// 实现MethodInterceptor接口,定义代理逻辑
public class CglibDynamicProxy implements MethodInterceptor {
    // 生成代理对象的方法
    public Object getProxyInstance(Class<?> targetClass) {
        Enhancer enhancer = new Enhancer();
        // 设置父类,即目标类
        enhancer.setSuperclass(targetClass);
        // 设置回调,即当前MethodInterceptor实例
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    // 代理对象调用方法时会执行这个方法
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("CGLIB动态代理:方法执行前,记录日志");
        // 调用目标对象的方法,通过MethodProxy的invokeSuper方法调用父类的方法
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("CGLIB动态代理:方法执行后,记录日志");
        return result;
    }
}

测试CGLIB动态代理的使用:

public class CglibDynamicProxyTest {
    public static void main(String[] args) {
        // 创建CGLIB代理实例
        CglibDynamicProxy proxy = new CglibDynamicProxy();
        // 获取代理对象
        OrderService orderService = (OrderService) proxy.getProxyInstance(OrderService.class);
        // 调用代理对象的方法
        orderService.createOrder("ORDER_001");
    }
}

静态代理和动态代理的核心差异

两者的核心差异可以通过下面的表格对比:

对比维度静态代理动态代理
代理类生成时机编译期手动编写,生成class文件运行期动态生成,不需要提前编写代理类
实现要求代理类和目标类需要实现相同接口JDK动态代理要求目标类实现接口;CGLIB不需要目标类实现接口
代码冗余度高,每个目标类或接口都需要对应一个代理类低,一个代理处理器可以处理多个目标类
灵活性低,代理逻辑修改需要修改代理类代码高,代理逻辑可以统一管理,修改方便
适用场景代理类少、接口稳定的简单场景需要批量代理、框架开发等复杂场景

使用场景总结

如果业务场景中需要代理的类很少,接口也比较稳定,静态代理的实现方式足够简单直观,不需要引入额外的复杂度。如果是在框架开发、AOP实现、RPC调用等需要批量生成代理的场景中,动态代理的优势会非常明显,能够大幅减少重复代码,提升开发和维护效率。在实际开发中,Spring框架的AOP功能就是基于动态代理实现的,默认情况下如果目标类实现了接口就使用JDK动态代理,否则使用CGLIB动态代理。

Java代理模式静态代理动态代理JDK动态代理CGLIB动态代理修改时间:2026-07-07 17:27:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。