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

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.dtcms.com/a/358747.html

相关文章:

  • MYSQL表结构优化场景
  • 解构机器学习:如何从零开始设计一个学习系统?
  • folium地图不显示加载不出来空白问题解决
  • SAP PP模块的MPS
  • 福彩双色球第2025100期篮球号码分析
  • git在push和clone等操作时显示‘: Invalid argument
  • 优选算法:二分查找
  • #5:Nginx核心使用技术
  • Java 学习笔记(基础篇12)
  • 小狼毫输入法中让数字键盘上的数字键不再选择候选词而是与原始输入一起直接上屏
  • 计算机视觉与深度学习 | 基于深度学习的图像特征提取与匹配算法综述及MATLAB实现
  • 互联网大厂大模型应用开发岗位面试:技术点详解与业务场景演练
  • nacos3端口漂移问题
  • shell编程-核心变量知识
  • LeetCode - 234. 回文链表
  • 2025年高性能计算年会
  • Golang 面试题「高级」
  • 零碳智慧园区双碳方案
  • 代理IP网站哪家好?全球优质IP代理服务商有什么推荐?
  • 【Linux】网络安全管理:Netfilter、nftables 与 Firewalld | Redhat
  • Linux查看Java进程PID、端口号和内存占用脚本
  • 2023年山东省信息学小学组(CSP-X)第一轮题解
  • 【嵌入式原理系列-第六篇】从Flash到RAM:MCU ld脚本全解析
  • SUMO 与 孪易 IOC 协同:开启交通数字孪生新纪元
  • 哪些人需要考道路运输安全员证?政策要求与适用范围
  • 计算机网络面试集合
  • 通过jar -jar启动jar包的yml配置logback 指定log目录
  • 2025-08-18面试题关于公司
  • 【计算机视觉】Pixel逐像素分类Mask掩码分类理解摘要
  • Git 远程仓库操作:推送到远程仓库、拉取远程仓库到本地仓库