JDK 动态代理CGLIB 动态代理 都是 Java 中实现 AOP(面向切面编程) 的常见方式,例如 Spring AOP 就使用这两种代理。

核心区别在于:代理对象生成方式不同


一、JDK 动态代理

JDK 动态代理是基于接口实现的代理。

它会在运行时 生成一个实现目标接口的代理类,然后在方法调用时进行拦截。

实现原理

JDK使用:

  • java.lang.reflect.Proxy
  • InvocationHandler

代理流程:

接口
 ↓
目标对象实现接口
 ↓
Proxy生成代理对象
 ↓
InvocationHandler拦截方法

示例代码

interface UserService {
    void login();
}

class UserServiceImpl implements UserService {
    public void login() {
        System.out.println("登录方法");
    }
}

代理实现:

UserService proxy = (UserService) Proxy.newProxyInstance(
        target.getClass().getClassLoader(),
        target.getClass().getInterfaces(),
        (proxyObj, method, args) -> {
            System.out.println("方法执行前");
            Object result = method.invoke(target, args);
            System.out.println("方法执行后");
            return result;
        }
);

特点

  • 必须有接口
  • 基于 反射机制
  • JDK自带,不需要第三方库

二、CGLIB 动态代理

CGLIB 是基于继承实现代理。

它会 生成目标类的子类,通过重写方法实现增强。

使用技术:

  • ASM字节码技术

代理流程:

目标类
 ↓
CGLIB生成子类
 ↓
重写方法
 ↓
MethodInterceptor拦截

示例代码

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);

enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
    System.out.println("方法执行前");
    Object result = proxy.invokeSuper(obj, args);
    System.out.println("方法执行后");
    return result;
});

UserServiceImpl proxy = (UserServiceImpl) enhancer.create();

三、核心区别

对比 JDK动态代理 CGLIB
实现方式 基于接口 基于继承
是否需要接口 必须需要 不需要
生成类方式 实现接口 生成子类
技术 反射 ASM字节码
final类 可以 不可以
final方法 可以 不能代理

四、Spring AOP 如何选择

Spring默认策略:

  • 如果有接口 → 使用 JDK 动态代理
  • 如果没有接口 → 使用 CGLIB

Spring Boot 2 之后 默认使用 CGLIB

也可以手动配置:

spring.aop.proxy-target-class=true

表示 强制使用 CGLIB


五、面试一句话总结

可以这样回答:

JDK 动态代理是基于接口实现的,通过 Proxy 和 InvocationHandler 在运行时生成代理类;而 CGLIB 是基于继承实现的,通过生成目标类的子类并重写方法进行增强。Spring AOP 默认优先使用 JDK 动态代理,如果没有接口则使用 CGLIB。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐