【从0开始学习Java | 第23篇】动态代理

【从0开始学习Java | 第23篇】动态代理
在这里插入图片描述

文章目录

Java动态代理概述

在Java开发中,代理模式设计模式之一,而动态代理作为代理模式的进阶形式,在框架开发(如Spring AOP)、日志记录、权限控制等场景中发挥着关键作用。本文将从核心概念出发,拆解两种主流动态代理的实现逻辑,并分析其适用场景。

在这里插入图片描述

一、动态代理的核心概念

动态代理指在程序运行时,通过反射机制动态生成代理类,而非在编译期预先定义。其核心价值在于:无需为每个目标类手动编写代理类,即可统一为多个目标类添加横切逻辑(如日志、事务、异常处理),降低代码耦合度。

在这里插入图片描述

动态代理包含三个核心角色:

  1. 目标类(Target):被代理的原始类,包含核心业务逻辑;
  2. 代理类(Proxy):运行时动态生成的类,持有目标类引用,负责调用目标方法并增强逻辑;
  3. 增强逻辑(Advice):需统一添加的横切逻辑,如日志打印、参数校验等。

形象解释

在这里插入图片描述

二、两种主流动态代理实现

Java中动态代理主要有两种实现方式:JDK动态代理(原生API)和CGLIB动态代理(第三方库),二者在原理和使用上存在显著差异。

1. JDK动态代理(基于接口)

原理

JDK动态代理依赖java.lang.reflect包下的ProxyInvocationHandler接口,要求目标类必须实现至少一个接口。运行时,JVM会动态生成一个实现目标接口的代理类,代理类的方法调用会转发到InvocationHandlerinvoke方法中,在该方法中可嵌入增强逻辑并调用目标方法。

在这里插入图片描述
示例代码
// 1. 定义接口publicinterfaceUserService{voidaddUser(String name);}// 2. 实现目标类publicclassUserServiceImplimplementsUserService{@OverridepublicvoidaddUser(String name){System.out.println("添加用户:"+ name);}}// 3. 实现InvocationHandler(增强逻辑)publicclassLogInvocationHandlerimplementsInvocationHandler{privateObject target;// 目标类引用publicLogInvocationHandler(Object target){this.target = target;}// 代理类的所有方法调用都会触发invoke@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{// 增强逻辑:前置日志System.out.println("方法"+ method.getName()+"开始执行,参数:"+Arrays.toString(args));// 调用目标方法Object result = method.invoke(target, args);// 增强逻辑:后置日志System.out.println("方法"+ method.getName()+"执行结束");return result;}}// 4. 生成代理类并测试publicclassJdkProxyTest{publicstaticvoidmain(String[] args){// 目标对象UserService target =newUserServiceImpl();// 生成代理对象(需传入类加载器、目标接口、InvocationHandler)UserService proxy =(UserService)Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(),newLogInvocationHandler(target));// 调用代理方法 proxy.addUser("张三");}}
优缺点
  • 优点:基于JDK原生API,无需依赖第三方库,轻量化;
  • 缺点:目标类必须实现接口,无法代理无接口的类。

2. CGLIB动态代理(基于子类)

原理

CGLIB(Code Generation Library)是一个第三方字节码生成库,通过生成目标类的子类作为代理类,无需目标类实现接口。其核心是MethodInterceptor接口,代理类的方法调用会被拦截到intercept方法中,在此处嵌入增强逻辑并调用目标方法。

示例代码(需引入CGLIB依赖)
<!-- Maven依赖 --><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency>
// 1. 目标类(无需实现接口)publicclassOrderService{publicvoidcreateOrder(String orderId){System.out.println("创建订单:"+ orderId);}}// 2. 实现MethodInterceptor(增强逻辑)publicclassLogMethodInterceptorimplementsMethodInterceptor{// 拦截代理类方法调用@OverridepublicObjectintercept(Object o,Method method,Object[] args,MethodProxy methodProxy)throwsThrowable{// 增强逻辑:前置日志System.out.println("方法"+ method.getName()+"开始执行,参数:"+Arrays.toString(args));// 调用目标方法(推荐用methodProxy.invokeSuper,避免递归调用)Object result = methodProxy.invokeSuper(o, args);// 增强逻辑:后置日志System.out.println("方法"+ method.getName()+"执行结束");return result;}}// 3. 生成代理类并测试publicclassCglibProxyTest{publicstaticvoidmain(String[] args){// CGLIB核心类:EnhancerEnhancer enhancer =newEnhancer();// 设置父类(目标类) enhancer.setSuperclass(OrderService.class);// 设置方法拦截器 enhancer.setCallback(newLogMethodInterceptor());// 生成代理对象(子类实例)OrderService proxy =(OrderService) enhancer.create();// 调用代理方法 proxy.createOrder("ORDER_001");}}
优缺点
  • 优点:无需目标类实现接口,可代理任意类(除final类和final方法);
  • 缺点:依赖第三方库,生成代理类时需操作字节码,性能略低于JDK动态代理(JDK 8后差距已缩小)。

三、JDK与CGLIB动态代理对比

对比维度JDK动态代理CGLIB动态代理
依赖JDK原生API(无第三方依赖)需引入CGLIB库
代理原理实现目标接口生成目标类子类
目标类要求必须实现接口无接口要求(不能是final类)
方法限制仅代理接口中的方法不能代理final方法
性能(JDK 8+)生成快,调用效率高生成慢,调用效率略低

四、实际应用场景

  1. Spring AOP:默认优先使用JDK动态代理(目标类有接口时),无接口时使用CGLIB;
  2. 日志记录:统一记录方法的入参、出参、执行时间;
  3. 权限控制:方法调用前校验用户权限,无权限则抛出异常;
  4. 事务管理:方法执行前开启事务,执行后提交/回滚事务。

五、总结

动态代理是Java中“解耦横切逻辑”的核心技术,JDK动态代理和CGLIB各有适用场景:若目标类已实现接口,优先选择JDK动态代理(轻量化、无依赖);若目标类无接口或需代理类的所有方法,选择CGLIB。


如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!

在这里插入图片描述

Read more

基于SpringBoot的企业考勤管理系统设计与实现

基于SpringBoot的企业考勤管理系统设计与实现

基于SpringBoot的企业考勤管理系统设计与实现 🌟 你好,我是 励志成为糕手 ! 🌌 在代码的宇宙中,我是那个追逐优雅与性能的星际旅人。 ✨ 每一行代码都是我种下的星光,在逻辑的土壤里生长成璀璨的银河; 🛠️ 每一个算法都是我绘制的星图,指引着数据流动的最短路径; 🔍 每一次调试都是星际对话,用耐心和智慧解开宇宙的谜题。 🚀 准备好开始我们的星际编码之旅了吗? 目录 * 基于SpringBoot的企业考勤管理系统设计与实现 * 摘要 * 系统架构设计 * 整体架构概览 * 核心业务流程 * 数据库设计 * 实体关系模型 * 数据表结构设计 * 核心代码实现 * 实体类设计 * 业务逻辑层实现 * 控制器层实现 * 系统功能特性 * 出勤状态管理 * 月度统计功能 * 技术选型对比 * 系统部署与配置 * 环境配置 * 项目依赖管理 * 系统性能优化 * 数据库优化策略 * 缓存策

By Ne0inhk
Flutter for OpenHarmony:Flutter 三方库 riverbloc — 融合 Bloc 与 Riverpod 的架构实践(适配鸿蒙 HarmonyOS Next ohos)

Flutter for OpenHarmony:Flutter 三方库 riverbloc — 融合 Bloc 与 Riverpod 的架构实践(适配鸿蒙 HarmonyOS Next ohos)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net。 前言 在鸿蒙(OpenHarmony)中大型项目中,开发者常在 Bloc 的严谨性与 Riverpod 的灵活性之间权衡。riverbloc 作为桥接库,允许将 Bloc 作为 Provider 管理,兼具了事件溯源与全局依赖注入的优势,是构建可维护业务中枢的理想选择。 一、核心价值 1.1 基础概念 riverbloc 引入了 BlocProvider 系列函数,使 Bloc 融入 Riverpod 的依赖树。 State 输出 ref.watch ref.read.add(Event) Riverpod ProviderContainer riverbloc 桥接层 触发业务逻辑

By Ne0inhk
用 Rust 打造二维码艺术大师:从想法到实现

用 Rust 打造二维码艺术大师:从想法到实现

二维码已经渗透到我们生活的方方面面,从支付到网站链接,几乎无处不在。但你有没有想过,二维码是怎么生成的?这些黑白方块也可以变得有趣和美观?今天我就来分享一下我用 Rust 实现的一个小项目:二维码艺术生成器(qr-artist)。 项目起源 这个想法源于一个简单的需求:如何让二维码既实用又美观?普通的黑白二维码虽然功能强大,但看起来有些单调。我想,能不能让二维码变得更有艺术感,比如用彩色像素来呈现? 技术选型 我选择了 Rust 作为开发语言,因为它在系统编程方面的优秀表现和内存安全特性。项目中主要使用了以下几个库: 1. qrcode - 用于生成二维码数据 2. image - 用于图像处理和保存 3. clap - 用于构建命令行界面 这些库都很成熟且文档完善,让我能够专注于核心功能的实现。 核心实现 1. 基础二维码生成 项目的核心是将 URL 转换为二维码数据,然后将其渲染为图像: // 创建二维码let code =QrCode::new(

By Ne0inhk

Go语言的主流框架和解决超高并发的三高微服务框架对比分析

在Go语言生态中,主流的Web框架和应对“三高”(高并发、高可用、高可扩展)场景的微服务框架,经过多年的发展已经非常清晰。简单来说,Gin 是目前应用最广泛的通用Web框架,而像 go-zero、Kratos、KiteX 等则是专为“三高”微服务架构设计的“全家桶”式解决方案。 下面为你详细拆解这两大类框架。 一、主流通用Web框架:轻量、灵活、高性能 这类框架主要解决API构建、路由和中间件管理等Web层问题,是构建单体应用或微服务API层的良好基础。 Gin:目前的“默认选项”,性能高、社区庞大、中间件丰富,极易上手。如果你刚开始接触Go或项目需求明确,选择Gin会非常稳妥。 Fiber:受Express.js启发,语法对Node.js开发者很友好。它基于fasthttp构建,在性能基准测试中表现极为出色。适合追求极致性能、且不介意与标准库net/http不完全兼容的场景。 Echo:一个成熟且平衡的框架,

By Ne0inhk