当前位置: 首页 > ds >正文

Jdk动态代理 Cglib动态代理

Jdk动态代理 & Cglib动态代理

一、Jdk动态代理

当调用Proxy.newProxyInstance()时,JDK会在内存中动态生成一个代理类,这个类大致如下:

public interface UserService{public String getUserById(int id);public void createUser(String name);
} 
public class UserServiceImpl implements UserService{public String getUserById(int id){// 执行实际方法。。。}public void createUser(String name){// 执行实际方法。。。}
} 
// JDK动态生成的代理类(伪代码)
public final class $Proxy0 extends Proxy implements UserService {private static Method m1;  // getUserById方法private static Method m2;  // createUser方法// 静态初始化块:通过反射获取Method对象static {try {m1 = Class.forName("UserService").getMethod("getUserById", int.class);m2 = Class.forName("UserService").getMethod("createUser", String.class);} catch (Exception e) {throw new Error(e);}}// 构造函数public $Proxy0(InvocationHandler h) {super(h);}// 重写接口方法 - 将调用转发给InvocationHandlerpublic String getUserById(int id) {try {// 这里传递预先获取的Method对象!return (String) super.h.invoke(this, m1, new Object[]{id});} catch (Throwable e) {throw new RuntimeException(e);}}// 重写接口方法public void createUser(String name) {try {// 这里传递预先获取的Method对象!super.h.invoke(this, m2, new Object[]{name});} catch (Throwable e) {throw new RuntimeException(e);}}
}
// 测试
public class MethodSourceExample {public static void main(String[] args) {// 创建出实际对象UserService realService = new UserServiceImpl();// 创建出代理对象UserService proxy = (UserService) Proxy.newProxyInstance(MethodSourceExample.class.getClassLoader(),// 类加载器new Class[]{UserService.class},// 类信息,作用是在创建代理对象时,可以通过这个信息调用反射API从而获取方法信息Methodnew InvocationHandler() {// 处理器,作用是当调用代理对象的方法实际上调用的是这个处理器的invoke方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 这个method参数就是JDK传递过来的!System.out.println("调用的方法: " + method.getName());System.out.println("方法参数: " + Arrays.toString(args));System.out.println("方法返回类型: " + method.getReturnType());return method.invoke(realService, args);}});// 调用方法 - 会自动传递对应的Method对象proxy.createUser("张三");String result = proxy.getUserById(123);}
}

总结:jdk代理对象实现了与实际对象一致的接口,重写了这个接口的所有方法。当调用代理对象的代理方法时,执行的就是处理器的invoke方法。这个invoke方法里可以通过反射调用到实际方法。

JDK代理基于接口、JDK代理使用反射调用、JDK代理可以代理接口中的默认方法。

二、Cglib动态代理

Cglib动态代理:它在运行时动态生成被代理类的子类,从而实现对类的代理。

// 目标类 - 不需要实现任何接口
class UserService {public void createUser(String name) {System.out.println("创建用户: " + name);}public void deleteUser(String name) {System.out.println("删除用户: " + name);}// 一个组合方法,内部调用其他方法public void manageUser(String name) {createUser(name);deleteUser(name);}// final方法,CGLIB无法代理public final void finalMethod() {System.out.println("这是一个final方法");}
}

// 方法拦截器 - 类似于JDK代理中的InvocationHandler
class LoggingInterceptor implements MethodInterceptor {// 前置通知方法private void beforeMethod() {System.out.println("[日志] 方法开始执行");}// 后置通知方法private void afterMethod() {System.out.println("[日志] 方法执行完成");}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {beforeMethod(); // 方法执行前的增强逻辑// 调用原始方法(通过MethodProxy)Object result = proxy.invokeSuper(obj, args);afterMethod(); // 方法执行后的增强逻辑return result;}
}
// 测试
public class CglibExample {public static void main(String[] args) {// 1. 创建Enhancer对象 - 用于生成代理类Enhancer enhancer = new Enhancer();// 2. 设置父类(被代理的类)enhancer.setSuperclass(UserService.class);// 3. 设置回调(方法拦截器)enhancer.setCallback(new LoggingInterceptor());// 4. 创建代理对象UserService userServiceProxy = (UserService) enhancer.create();System.out.println("=== 调用单个方法 ===");userServiceProxy.createUser("张三");System.out.println("\n=== 调用组合方法 ===");userServiceProxy.manageUser("李四");System.out.println("\n=== 调用final方法 ===");userServiceProxy.finalMethod();}
}
// 伪代码:CGLIB生成的代理类大致结构
public class UserService$$EnhancerByCGLIB extends UserService {private MethodInterceptor interceptor;private static final MethodProxy methodProxy1;private static final MethodProxy methodProxy2;static {// 静态初始化:创建MethodProxy对象}// 重写父类方法public void createUser(String name) {// 调用拦截器interceptor.intercept(this, Method对象表示createUser, new Object[]{name}, MethodProxy对象);}// 其他方法类似...
}

三、Cglib动态代理特点

MethodProxy的作用:

public class MethodProxy {public Object invokeSuper(Object obj, Object[] args) {// 使用FastClass快速调用父类方法return fastClassInfoProxy.invoke(methodIndex, obj, args);}
}

FastClass的工作原理:

FastClass为每个方法分配唯一索引,通过索引直接调用方法:

// FastClass的近似实现
public class FastClass {public Object invoke(int index, Object obj, Object[] args) {switch (index) {case 0: return ((TargetClass)obj).method1((String)args[0]);case 1: return ((TargetClass)obj).method2((Integer)args[0]);// ...}}
}

在这里插入图片描述

CGLIB选择字节码分析是因为它能代理普通类,知道被代理的类里的各个方法信息。而JDK动态代理只能代理接口,而接口的方法信息通过反射API就能完整获取,因此不需要复杂的字节码分析。因此CGLIB代理能通过方法索引直接调用,避免反射开销。

四、CGLIB的优势与局限

1. 优势

  • 高性能:FastClass机制使方法调用接近直接调用速度
  • 灵活性:可以代理普通类,不仅仅是接口
  • 功能强大:支持复杂的方法拦截和增强场景

2. 局限性

  • 不能代理final类和方法:因为基于继承机制
  • 创建开销较大:字节码分析和生成比JDK代理更耗时
  • 依赖ASM库:需要额外的第三方依赖

五、实际应用场景

1. Spring框架中的应用

// Spring配置强制使用CGLIB代理
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {// ...
}

2. 适用场景

  • 代理没有实现接口的类
  • 需要高性能方法调用的场景
  • 需要代理私有方法的特殊场景
http://www.xdnf.cn/news/19362.html

相关文章:

  • Linux 定时器:工作原理与实现机制深入分析
  • STL库——list(类模拟实现)
  • 复制VMware虚拟机后的网络配置
  • 算法---动态规划(持续更新学习)
  • k230 按键拍照后,将摄像头拍照的1920*1080分辨率的图片以jpg文件格式,保存到板载TF存储卡的指定文件夹目录中
  • 营业执照经营范围行业提取工具库项目方案解读(php封装库)
  • 项目管理在企业中的作用
  • Python 多线程日志错乱:logging.Handler 的并发问题
  • 什么是IO多路复用
  • ESPTimer vs GPTimer:ESP32 定时器系统深度解析
  • 【Java基础知识 19】继承
  • Spring注解演进与自动装配原理深度解析:从历史发展到自定义Starter实践
  • 197-200CSS3响应式布局,BFC
  • 内存管理(智能指针,内存对齐,野指针,悬空指针)
  • 时间轴组件开发:实现灵活的时间范围选择
  • PHP单独使用phinx使用数据库迁移
  • Spring Cloud微服务架构设计与实战:从组件落地到分布式事务解决
  • 精简版UDP网络编程:Socket套接字应用
  • 链表有环找入口节点原理
  • css绘制三角形
  • A股大盘数据-20250829 分析
  • C++基础(③反转字符串(字符串 + 双指针))
  • 阿里巴巴拍立淘API返回值解析与商品信息优化指南
  • 刷题日记0829
  • Libvio 访问异常排查指南
  • OpenEuler部署LoganaLyzer
  • linux实时性研究
  • Python 编码与加密全解析:从字符编码到 RSA 签名验证
  • Win11 压缩实测:Win11 的压缩软件的最佳配置和使用方式
  • 龙迅#LT7621GX适用于两路HDMI2.1/DP1.4A转HDMI2.1混切应用,分辨率高达8K60HZ!