Java动态代理详解

Java 动态代理

Java 的动态代理(Dynamic Proxy)是 Java 反射机制的重要应用之一,主要用于AOP(面向切面编程)、权限控制、日志记录、事务管理等场景。动态代理分为两种方式:

  1. JDK 动态代理(基于接口)
  2. CGLIB 动态代理(基于子类继承)

1. JDK 动态代理

JDK 动态代理依赖 Java 的 java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler,只能代理实现了接口的类

示例

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

// 1. 定义接口
interface Service {
    void doSomething();
}

// 2. 目标对象(被代理对象)
class RealService implements Service {
    public void doSomething() {
        System.out.println("业务逻辑执行中...");
    }
}

// 3. 创建动态代理处理器
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;
    }
}

// 4. 生成代理对象
public class JDKProxyExample {
    public static void main(String[] args) {
        // 创建目标对象
        Service realService = new RealService();

        // 生成代理对象
        Service proxyService = (Service) Proxy.newProxyInstance(
                realService.getClass().getClassLoader(), 
                new Class[]{Service.class}, 
                new MyInvocationHandler(realService)
        );

        // 调用代理方法
        proxyService.doSomething();
    }
}

输出

方法执行前的操作...
业务逻辑执行中...
方法执行后的操作...

JDK 动态代理特点

优点

  • 无需手写代理类,利用 Proxy 生成代理对象,避免硬编码。
  • 支持 AOP,可在方法调用前后加入额外逻辑(如日志、事务)。
  • 性能较好(比反射调用快)。

⚠️ 缺点

  • 只能代理接口,不能代理普通类。
  • 底层使用反射,性能比 CGLIB 略差

2. CGLIB 动态代理

CGLIB(Code Generation Library) 是一个基于字节码增强的库,可以代理没有实现接口的类,底层使用 ASM 直接操作字节码,性能比 JDK 代理更优。

示例

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

// 1. 目标类(没有实现接口)
class RealService {
    public void doSomething() {
        System.out.println("业务逻辑执行中...");
    }
}

// 2. 创建 CGLIB 代理拦截器
class CglibProxyHandler implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("方法执行前的操作...");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("方法执行后的操作...");
        return result;
    }
}

// 3. 生成代理对象
public class CglibProxyExample {
    public static void main(String[] args) {
        // 创建 Enhancer
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealService.class); // 设置目标类
        enhancer.setCallback(new CglibProxyHandler()); // 设置回调拦截器

        // 创建代理对象
        RealService proxyService = (RealService) enhancer.create();

        // 调用代理方法
        proxyService.doSomething();
    }
}

输出

方法执行前的操作...
业务逻辑执行中...
方法执行后的操作...

CGLIB 动态代理特点

优点

  • 支持代理普通类,不要求目标类必须实现接口。
  • 性能比 JDK 动态代理更优(因为直接操作字节码)。
  • Spring AOP 默认使用 CGLIB(除非目标对象实现了接口)。

⚠️ 缺点

  • 不能代理 final 方法(因为 CGLIB 依赖子类继承)。
  • 生成的代理类比 JDK 代理类体积大

3. JDK 代理 vs CGLIB 代理

方式代理对象要求代理方式性能
JDK 代理需要实现接口反射调用一般
CGLIB 代理不需要接口直接修改字节码更快

选择建议

  • 如果类实现了接口,优先使用 JDK 动态代理(默认方式)。
  • 如果类没有接口,使用 CGLIB 动态代理
  • Spring AOP 默认使用 JDK 代理(如果类实现了接口),否则使用 CGLIB

4. Spring AOP 与动态代理

Spring 的 AOP 主要使用JDK 动态代理CGLIB,默认策略如下:

  • 如果目标类实现了接口 → 使用 JDK 动态代理
  • 如果目标类没有实现接口 → 使用 CGLIB 代理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

归屿-code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值