rokevin
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
  • 动态代理

  • 目前主流的动态代理方案(共 5 种)
  • 目前主流的动态代理方案(共 5 种)
  • 总览(先记这张表)
  • 1. JDK 动态代理
    • 核心原理
    • 适用场景
    • 完整代码
      • 接口
      • 实现类
      • 代理处理器
      • 测试
    • 优点
    • 缺点
  • 2. CGLIB
    • 核心原理
    • 适用场景
    • 依赖
    • 代码
    • 优点
    • 缺点
  • 3. ByteBuddy(🔥 现代王者)
    • 核心原理
    • 适用场景
    • 依赖
    • 代码
    • 优点
    • 缺点
  • 4. Javassist
    • 核心原理
    • 适用场景
    • 依赖
    • 代码
    • 优点
    • 缺点
  • 5. ASM(最底层)
    • 核心原理
    • 适用场景
    • 优点
    • 缺点
  • 五大方案 终极对比(面试满分)
    • 1. 代理能力
    • 2. 性能
    • 3. 编码难度
    • 4. 现代企业选择
  • 一句话总结(背会直接封神)
  • Java五大动态代理面试10题
    • 一、基础必考题
      • Java动态代理有哪些主流方案?请简要说明。
      • JDK动态代理为什么只能代理接口?
      • CGLIB动态代理的原理是什么?有什么限制?
      • ByteBuddy相比CGLIB有什么优势?为什么Spring替换了CGLIB?
      • 面试官:Javassist的核心特点是什么?主要用在什么场景?
    • 二、进阶高频题
      • 面试官:JDK动态代理和CGLIB的核心区别(至少3点)?
      • 面试官:ASM为什么不适合业务开发?它的核心用途是什么?
      • 面试官:实际开发中,如何选择动态代理方案?
    • 三、深度拓展题
      • 面试官:JDK动态代理的调用链路是什么?
      • 面试官:ByteBuddy、CGLIB、ASM的性能排序,以及为什么?

动态代理

目前主流的动态代理方案(共 5 种)

  1. JDK 动态代理(只能代理接口)
  2. CGLIB(继承类做代理)
  3. ByteBuddy(现代最强大、Spring 已替换 CGLIB)
  4. Javassist(JBoss、MyBatis 常用)
  5. ASM(最底层、性能最高,框架底层用)

目前主流的动态代理方案(共 5 种)

  1. JDK 动态代理(只能代理接口)
  2. CGLIB(继承类做代理)
  3. ByteBuddy(现代最强大、Spring 已替换 CGLIB)
  4. Javassist(JBoss、MyBatis 常用)
  5. ASM(最底层、性能最高,框架底层用)

总览(先记这张表)

方案原理代理目标性能难度核心用途
JDK 动态代理实现接口 + 继承 Proxy只能接口高极低Spring AOP(默认)
CGLIB继承目标类 + ASM类/接口高中旧版 Spring
ByteBuddy继承/实现接口 + 底层ASM类/接口极高低Spring Boot 2.x+ 默认
Javassist字符串拼接代码类/接口中极低MyBatis Mapper 代理
ASM直接操作字节码指令任意最高地狱框架底层、中间件

1. JDK 动态代理

核心原理

  • 动态生成类:$Proxy0 extends Proxy implements 目标接口
  • 所有方法通过反射转发到 InvocationHandler
  • 只能代理接口

适用场景

  • 目标类有接口
  • Spring AOP 默认方案

完整代码

接口

public interface UserService {
    void addUser(String name);
}

实现类

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

代理处理器

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

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(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;
    }
}

测试

import java.lang.reflect.Proxy;

public class JdkProxyTest {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new MyInvocationHandler(target)
        );
        proxy.addUser("JDK");
    }
}

优点

  • JDK 原生,无需依赖
  • 简单稳定
  • 高版本 JDK 性能优秀

缺点

  • 只能代理接口

2. CGLIB

核心原理

  • 生成目标类的子类
  • 重写非 final 方法
  • 用 FastClass 避免反射

适用场景

  • 目标类没有接口
  • 旧版 Spring AOP

依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

代码

import net.sf.cglib.proxy.*;

public class CglibTest {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserServiceImpl.class); // 继承目标类
        enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
            System.out.println("前置");
            Object res = proxy.invokeSuper(obj, args);
            System.out.println("后置");
            return res;
        });
        UserServiceImpl proxy = (UserServiceImpl) enhancer.create();
        proxy.addUser("CGLIB");
    }
}

优点

  • 可代理普通类
  • 性能不错

缺点

  • 不能代理 final 类/方法
  • 已被 ByteBuddy 替代

3. ByteBuddy(🔥 现代王者)

核心原理

  • 底层 ASM
  • 支持继承/实现接口
  • API 优雅,性能接近 ASM
  • Spring 默认

适用场景

  • Spring AOP
  • 动态代理、类增强
  • 现代框架首选

依赖

<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>1.14.10</version>
</dependency>

代码

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import static net.bytebuddy.matcher.ElementMatchers.*;

public class ByteBuddyTest {
    public static void main(String[] args) throws Exception {
        // 生成 UserService 子类
        Class<? extends UserServiceImpl> proxyClass = new ByteBuddy()
                .subclass(UserServiceImpl.class)
                .method(named("addUser"))
                .intercept(MethodDelegation.to(new MyInterceptor()))
                .make()
                .load(UserServiceImpl.class.getClassLoader())
                .getLoaded();

        UserServiceImpl proxy = proxyClass.newInstance();
        proxy.addUser("ByteBuddy");
    }
}

// 拦截器
class MyInterceptor {
    public void intercept() {
        System.out.println("前置增强");
        // 调用原方法
        System.out.println("后置增强");
    }
}

优点

  • 性能极高
  • API 优雅
  • 可代理类/接口
  • Spring 官方推荐

缺点

  • 依赖第三方包

4. Javassist

核心原理

  • 用字符串写 Java 代码
  • 动态编译成字节码
  • 简单到极致

适用场景

  • MyBatis Mapper 代理
  • 动态生成简单类

依赖

<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.30.2-GA</version>
</dependency>

代码

import javassist.util.proxy.*;

public class JavassistTest {
    public static void main(String[] args) throws Exception {
        ProxyFactory factory = new ProxyFactory();
        factory.setSuperclass(UserServiceImpl.class);

        MethodHandler handler = (self, thisMethod, proceed, args) -> {
            System.out.println("前置");
            Object res = proceed.invoke(self, args);
            System.out.println("后置");
            return res;
        };

        UserServiceImpl proxy = (UserServiceImpl) factory.createClass().newInstance();
        ((ProxyObject) proxy).setHandler(handler);
        proxy.addUser("Javassist");
    }
}

优点

  • 最简单
  • 字符串拼代码即可

缺点

  • 性能略低
  • 复杂场景难维护

5. ASM(最底层)

核心原理

  • 直接操作 JVM 字节码指令
  • 性能天花板
  • 难度极高

适用场景

  • 框架底层
  • CGLIB / ByteBuddy 底层
  • APM、热部署

优点

  • 性能最高
  • 最灵活

缺点

  • 必须懂字节码
  • 开发效率极低

五大方案 终极对比(面试满分)

1. 代理能力

  • JDK:只能接口
  • CGLIB:类(不能final)
  • ByteBuddy:类/接口(全能)
  • Javassist:类/接口
  • ASM:任意

2. 性能

ASM > ByteBuddy > CGLIB >= JDK > Javassist

3. 编码难度

ASM >>> CGLIB > ByteBuddy > JDK > Javassist

4. 现代企业选择

  • 有接口:JDK
  • 无接口:ByteBuddy(Spring 默认)
  • 快速开发:Javassist
  • 框架底层:ASM
  • CGLIB 已淘汰

一句话总结(背会直接封神)

  1. JDK:只能代理接口,原生简单。
  2. CGLIB:继承类代理,已过时。
  3. ByteBuddy:现代最强,Spring 默认,性能+易用完美。
  4. Javassist:最简单,字符串拼代码,MyBatis 在用。
  5. ASM:最底层、最快、最难,框架基石。

Java五大动态代理面试10题

一、基础必考题

Java动态代理有哪些主流方案?请简要说明。

共5种,核心3种常用。① JDK动态代理(原生,只能代理接口);② CGLIB(继承目标类,已被淘汰);③ ByteBuddy(现代首选,Spring Boot 2.x+默认);④ Javassist(简单,MyBatis在用);⑤ ASM(最底层,框架底层使用)。

JDK动态代理为什么只能代理接口?

核心是Java单继承限制。JDK动态代理运行时生成的代理类,会强制继承Proxy类,一个类只能有一个直接父类,无法再继承目标业务类,因此只能通过实现接口的方式完成代理。

CGLIB动态代理的原理是什么?有什么限制?

原理是通过ASM生成目标类的子类,重写非final方法,通过FastClass机制(方法索引)直接调用目标方法,避免反射。限制:不能代理final类、final方法,也不能代理static方法。

ByteBuddy相比CGLIB有什么优势?为什么Spring替换了CGLIB?

优势有3点:① 性能更优,接近ASM;② API更优雅,支持链式编程,开发效率高;③ 功能更强大,支持继承/实现接口两种代理方式,兼容性更好。Spring替换CGLIB,是因为ByteBuddy在性能和易用性上实现了完美平衡,且更适配现代框架开发。

面试官:Javassist的核心特点是什么?主要用在什么场景?

核心特点是简单易用,支持通过字符串拼接Java代码,动态编译成字节码,无需懂字节码指令。主要场景:MyBatis的Mapper代理、快速开发简单的动态类增强需求。

二、进阶高频题

面试官:JDK动态代理和CGLIB的核心区别(至少3点)?

① 代理原理:JDK是实现接口+继承Proxy,CGLIB是继承目标类;② 代理目标:JDK只能代理接口,CGLIB可代理普通类;③ 调用方式:JDK用反射调用,CGLIB用FastClass直接调用;④ 限制:JDK依赖接口,CGLIB不能代理final类/方法。

面试官:ASM为什么不适合业务开发?它的核心用途是什么?

因为ASM直接操作JVM字节码指令,开发难度极高,需要熟练掌握字节码规范,开发效率极低,容易出错,因此不适合业务开发。核心用途:作为所有动态代理工具的底层引擎(如CGLIB、ByteBuddy),以及框架底层、APM监控、热部署等场景。

面试官:实际开发中,如何选择动态代理方案?

优先遵循Spring的选择:① 目标类有接口:用JDK动态代理(原生、稳定);② 目标类无接口:用ByteBuddy(Spring默认,性能优);③ 快速开发简单需求:用Javassist;④ 框架/中间件开发:用ASM(追求极致性能);⑤ 不推荐用CGLIB(已被ByteBuddy替代)。

三、深度拓展题

面试官:JDK动态代理的调用链路是什么?

调用链路:代理对象调用方法 → 动态生成的$Proxy0类的对应方法 → 转发到InvocationHandler的invoke方法 → 执行增强逻辑 + 反射调用目标对象的方法 → 返回结果。

面试官:ByteBuddy、CGLIB、ASM的性能排序,以及为什么?

性能排序:ASM > ByteBuddy > CGLIB。原因:① ASM直接操作字节码,无任何额外封装,性能最高;② ByteBuddy底层基于ASM,封装了优雅的API,但几乎没有性能损耗,接近ASM;③ CGLIB同样基于ASM,但封装层次更多,且FastClass机制的性能略逊于ByteBuddy的优化逻辑。

最近更新:: 2026/4/2 20:07
Contributors: luokaiwen