JAVA 动态代理:从原理剖析到实战应用

JAVA 动态代理:从原理剖析到实战应用

JAVA 动态代理:从原理剖析到实战应用

在这里插入图片描述

1.1 本章学习目标与重点

💡 掌握动态代理的核心概念与分类,理解动态代理在 Java 开发中的核心价值。
💡 熟练掌握 JDK 动态代理的实现流程与核心 API,能够独立编写 JDK 动态代理代码。
💡 了解 CGLIB 动态代理的实现原理与适用场景,对比 JDK 动态代理与 CGLIB 动态代理的差异。
💡 结合实际业务场景,掌握动态代理在 AOP 编程、权限控制、日志记录等场景中的实战应用。
⚠️ 本章重点是 JDK 动态代理的核心实现动态代理在 AOP 中的实战应用,这是 Java 高级开发与框架设计的必备技能。

1.2 动态代理的核心概念与价值

1.2.1 什么是动态代理

💡 动态代理 是 Java 设计模式中代理模式的一种高级实现,它允许程序在 运行时 动态生成目标类的代理对象,而无需在编译期手动编写代理类的代码。

在传统的静态代理模式中,我们需要为每个目标类手动编写对应的代理类,代理类与目标类实现相同的接口,这种方式存在代码冗余、扩展性差的问题。而动态代理则通过反射机制,在运行时动态创建代理类,实现了代理逻辑的复用,大幅提升了代码的灵活性和扩展性。

动态代理的核心思想是 “代理对象包裹目标对象,增强目标对象的方法功能”,代理对象可以在目标方法执行前后添加额外的逻辑,如日志记录、权限校验、事务管理等,而不需要修改目标对象的代码。

1.2.2 动态代理的核心价值

动态代理是 Java 高级开发中不可或缺的技术,其核心价值主要体现在以下几个方面:

  1. 解耦核心业务与非核心业务:将日志、事务、权限等通用功能从核心业务代码中抽离,实现 关注点分离
  2. 提升代码复用性:代理逻辑可以复用在多个目标类上,避免重复编写相同的增强代码。
  3. 增强代码扩展性:新增增强功能时,只需修改代理逻辑,无需修改目标类代码,符合 开闭原则
  4. 框架开发的核心基石:是 Spring AOP、MyBatis 等主流框架的底层实现技术,支撑了框架的核心功能。

1.2.3 动态代理的分类

根据实现方式的不同,Java 中的动态代理主要分为两类:

动态代理类型底层实现核心要求典型应用
JDK 动态代理Java 反射机制目标类必须实现一个或多个接口Spring AOP(默认)、自定义框架
CGLIB 动态代理字节码增强技术(ASM 框架)目标类可以不实现接口,不能是 final 类Spring AOP(目标类无接口时)、Hibernate

✅ 核心结论:动态代理的本质是 运行时生成代理类,增强目标方法功能,它是实现 AOP 编程的核心技术。

1.3 代理模式基础:静态代理

在学习动态代理之前,我们需要先掌握静态代理的实现方式,理解代理模式的核心思想,为动态代理的学习打下基础。

1.3.1 静态代理的核心角色

静态代理模式包含三个核心角色:

  1. 抽象角色:通常是一个接口,定义了目标对象和代理对象的共同方法。
  2. 目标角色:实现抽象角色的类,是代理对象所代理的真实对象,包含核心业务逻辑。
  3. 代理角色:实现抽象角色的类,包含对目标对象的引用,在目标方法执行前后添加增强逻辑。

1.3.2 静态代理的代码实现

/** * 静态代理示例:用户服务接口(抽象角色) */publicinterfaceUserService{voidaddUser(String username);voiddeleteUser(String userId);}/** * 目标角色:用户服务实现类 */publicclassUserServiceImplimplementsUserService{@OverridepublicvoidaddUser(String username){System.out.println("核心业务:添加用户 "+ username);}@OverridepublicvoiddeleteUser(String userId){System.out.println("核心业务:删除用户 "+ userId);}}/** * 代理角色:用户服务代理类 */publicclassUserServiceProxyimplementsUserService{// 维护目标对象的引用privatefinalUserService target;publicUserServiceProxy(UserService target){this.target = target;}@OverridepublicvoidaddUser(String username){// 前置增强:日志记录System.out.println("[日志] 执行 addUser 方法,参数:"+ username);// 执行目标方法 target.addUser(username);// 后置增强:事务提交System.out.println("[事务] 添加用户成功,事务提交");}@OverridepublicvoiddeleteUser(String userId){// 前置增强:日志记录System.out.println("[日志] 执行 deleteUser 方法,参数:"+ userId);// 执行目标方法 target.deleteUser(userId);// 后置增强:事务提交System.out.println("[事务] 删除用户成功,事务提交");}}/** * 测试类 */publicclassStaticProxyTest{publicstaticvoidmain(String[] args){// 创建目标对象UserService target =newUserServiceImpl();// 创建代理对象UserService proxy =newUserServiceProxy(target);// 通过代理对象调用方法 proxy.addUser("张三");System.out.println("---------------------------"); proxy.deleteUser("1001");}}

1.3.3 静态代理的优缺点

优点

  • 实现简单,易于理解和上手。
  • 不修改目标类代码,实现了核心业务与增强逻辑的分离。

缺点

  • 代码冗余:每个目标类都需要编写对应的代理类,当目标类较多时,代理类数量会急剧增加。
  • 扩展性差:新增增强功能时,需要修改所有代理类的代码。
  • 耦合度高:代理类与目标类实现相同的接口,接口变更时,代理类和目标类都需要修改。

⚠️ 注意事项:静态代理的缺点正是动态代理需要解决的问题,动态代理通过运行时生成代理类,完美解决了静态代理的代码冗余和扩展性问题。

1.4 JDK 动态代理核心实现

JDK 动态代理是 Java 官方提供的动态代理实现,底层基于 反射机制java.lang.reflect 包下的核心 API 实现。

1.4.1 JDK 动态代理的核心 API

JDK 动态代理的核心 API 包含两个关键类/接口:

  1. InvocationHandler 接口:这是调用处理器接口,代理对象的所有方法调用都会转发到该接口的 invoke 方法,我们需要实现该接口来编写增强逻辑。
  2. Proxy:这是代理类的生成器,通过其静态方法 newProxyInstance 可以在运行时动态生成代理对象。
核心方法详解
  • InvocationHandler.invoke(Object proxy, Method method, Object[] args)
    • proxy:生成的代理对象本身
    • method:被调用的目标方法对象
    • args:目标方法的参数数组
    • 作用:编写增强逻辑,并通过反射调用目标方法
  • Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
    • loader:目标类的类加载器
    • interfaces:目标类实现的接口数组
    • h:调用处理器对象
    • 作用:生成并返回动态代理对象

1.4.2 JDK 动态代理的实现步骤

💡 JDK 动态代理的实现可以分为以下四个核心步骤:
① 定义业务接口和目标类
② 实现 InvocationHandler 接口,编写增强逻辑
③ 通过 Proxy.newProxyInstance 生成代理对象
④ 通过代理对象调用目标方法

1.4.3 JDK 动态代理的代码实现

importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;/** * 步骤1:定义业务接口和目标类(复用静态代理的 UserService 和 UserServiceImpl) */publicinterfaceUserService{voidaddUser(String username);voiddeleteUser(String userId);}publicclassUserServiceImplimplementsUserService{@OverridepublicvoidaddUser(String username){System.out.println("核心业务:添加用户 "+ username);}@OverridepublicvoiddeleteUser(String userId){System.out.println("核心业务:删除用户 "+ userId);}}/** * 步骤2:实现 InvocationHandler 接口,编写增强逻辑 */publicclassLogTransactionInvocationHandlerimplementsInvocationHandler{// 维护目标对象的引用privatefinalObject target;publicLogTransactionInvocationHandler(Object target){this.target = target;}@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{Object result =null;try{// 前置增强:日志记录System.out.println("[日志] 执行方法:"+ method.getName()+",参数:"+(args ==null?"无": args[0]));// 反射调用目标方法 result = method.invoke(target, args);// 后置增强:事务提交System.out.println("[事务] 方法执行成功,事务提交");}catch(Exception e){// 异常增强:事务回滚System.out.println("[事务] 方法执行异常,事务回滚,异常信息:"+ e.getMessage());throw e;}return result;}}/** * 步骤3和4:生成代理对象并测试 */publicclassJdkDynamicProxyTest{publicstaticvoidmain(String[] args){// 1. 创建目标对象UserService target =newUserServiceImpl();// 2. 创建调用处理器对象InvocationHandler handler =newLogTransactionInvocationHandler(target);// 3. 生成动态代理对象UserService proxy =(UserService)Proxy.newProxyInstance( target.getClass().getClassLoader(),// 目标类的类加载器 target.getClass().getInterfaces(),// 目标类实现的接口 handler // 调用处理器);// 4. 通过代理对象调用方法System.out.println("===== 正常调用 ====="); proxy.addUser("李四");System.out.println("---------------------------"); proxy.deleteUser("1002");System.out.println("\n===== 异常调用 =====");// 模拟方法执行异常try{ proxy.addUser(null);}catch(Exception e){// 捕获异常}}}

1.4.4 运行结果与分析

===== 正常调用 ===== [日志] 执行方法:addUser,参数:李四 核心业务:添加用户 李四 [事务] 方法执行成功,事务提交 --------------------------- [日志] 执行方法:deleteUser,参数:1002 核心业务:删除用户 1002 [事务] 方法执行成功,事务提交 ===== 异常调用 ===== [日志] 执行方法:addUser,参数:null 核心业务:添加用户 null [事务] 方法执行异常,事务回滚,异常信息:null 

✅ 核心结论:JDK 动态代理通过 InvocationHandler 统一处理所有目标方法的增强逻辑,实现了代理逻辑的复用,解决了静态代理的代码冗余问题。

1.4.5 JDK 动态代理的注意事项

⚠️ 1. 目标类必须实现接口:JDK 动态代理是基于接口实现的,如果目标类没有实现任何接口,Proxy.newProxyInstance 方法会抛出 IllegalArgumentException 异常。
⚠️ 2. 代理对象是接口的实现类:通过 JDK 动态代理生成的代理对象,是目标类所实现接口的子类,不能将代理对象强制转换为目标类类型。
⚠️ 3. 增强逻辑统一化:所有目标方法的增强逻辑都写在 invoke 方法中,如果需要对不同方法进行不同增强,可以通过 method.getName() 进行判断。

1.5 CGLIB 动态代理核心实现

CGLIB(Code Generation Library)是一个基于字节码增强技术的动态代理框架,它弥补了 JDK 动态代理的不足,支持对没有实现接口的类进行代理。

1.5.1 CGLIB 动态代理的核心原理

CGLIB 动态代理的底层基于 ASM 字节码操作框架,它的核心原理是:

  1. 在运行时动态生成目标类的 子类,并重写目标类的非 final 方法。
  2. 在子类中嵌入增强逻辑,实现对目标方法的增强。
  3. 通过创建子类的实例,作为目标类的代理对象。

1.5.2 CGLIB 动态代理的核心 API

CGLIB 动态代理的核心 API 包含两个关键类:

  1. MethodInterceptor 接口:方法拦截器接口,类似于 JDK 动态代理的 InvocationHandler,代理对象的方法调用会转发到该接口的 intercept 方法。
  2. Enhancer:增强器类,用于生成目标类的子类(代理对象)。

1.5.3 CGLIB 动态代理的实现步骤

💡 CGLIB 动态代理的实现步骤如下:
① 引入 CGLIB 依赖
② 定义目标类(可以不实现接口)
③ 实现 MethodInterceptor 接口,编写增强逻辑
④ 通过 Enhancer 生成代理对象
⑤ 通过代理对象调用目标方法

1.5.4 CGLIB 动态代理的代码实现

步骤1:引入 CGLIB 依赖(Maven)
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency>
步骤2:编写目标类(无接口)
/** * 目标类:订单服务类(无实现任何接口) */publicclassOrderService{publicvoidcreateOrder(String orderId){System.out.println("核心业务:创建订单 "+ orderId);}publicvoidcancelOrder(String orderId){System.out.println("核心业务:取消订单 "+ orderId);}}
步骤3:实现 MethodInterceptor 接口
importnet.sf.cglib.proxy.MethodInterceptor;importnet.sf.cglib.proxy.MethodProxy;importjava.lang.reflect.Method;/** * CGLIB 方法拦截器:编写增强逻辑 */publicclassLogMethodInterceptorimplementsMethodInterceptor{/** * @param obj 代理对象(目标类的子类实例) * @param method 目标方法对象 * @param args 目标方法参数 * @param proxy 方法代理对象,用于调用目标方法 */@OverridepublicObjectintercept(Object obj,Method method,Object[] args,MethodProxy proxy)throwsThrowable{Object result =null;try{// 前置增强:日志记录System.out.println("[CGLIB 日志] 执行方法:"+ method.getName()+",参数:"+(args ==null?"无": args[0]));// 调用目标方法(通过 MethodProxy 调用,性能更高) result = proxy.invokeSuper(obj, args);// 后置增强:事务提交System.out.println("[CGLIB 事务] 方法执行成功,事务提交");}catch(Exception e){// 异常增强:事务回滚System.out.println("[CGLIB 事务] 方法执行异常,事务回滚,异常信息:"+ e.getMessage());throw e;}return result;}}
步骤4:生成代理对象并测试
importnet.sf.cglib.proxy.Enhancer;/** * CGLIB 动态代理测试类 */publicclassCglibDynamicProxyTest{publicstaticvoidmain(String[] args){// 1. 创建增强器对象Enhancer enhancer =newEnhancer();// 2. 设置目标类的字节码(父类) enhancer.setSuperclass(OrderService.class);// 3. 设置方法拦截器 enhancer.setCallback(newLogMethodInterceptor());// 4. 生成代理对象(目标类的子类实例)OrderService proxy =(OrderService) enhancer.create();// 5. 通过代理对象调用方法System.out.println("===== 正常调用 ====="); proxy.createOrder("ORDER_20260129");System.out.println("---------------------------"); proxy.cancelOrder("ORDER_20260129");System.out.println("\n===== 异常调用 =====");try{ proxy.createOrder(null);}catch(Exception e){// 捕获异常}}}

1.5.5 运行结果与分析

===== 正常调用 ===== [CGLIB 日志] 执行方法:createOrder,参数:ORDER_20260129 核心业务:创建订单 ORDER_20260129 [CGLIB 事务] 方法执行成功,事务提交 --------------------------- [CGLIB 日志] 执行方法:cancelOrder,参数:ORDER_20260129 核心业务:取消订单 ORDER_20260129 [CGLIB 事务] 方法执行成功,事务提交 ===== 异常调用 ===== [CGLIB 日志] 执行方法:createOrder,参数:null 核心业务:创建订单 null [CGLIB 事务] 方法执行异常,事务回滚,异常信息:null 

1.5.6 CGLIB 动态代理的注意事项

⚠️ 1. 目标类不能是 final 类:CGLIB 通过生成子类实现代理,如果目标类是 final 类,无法生成子类,会抛出 IllegalArgumentException 异常。
⚠️ 2. 目标方法不能是 final 方法:final 方法不能被子类重写,因此无法被 CGLIB 增强。
⚠️ 3. 性能优于 JDK 动态代理:CGLIB 基于字节码操作,直接生成字节码,性能比基于反射的 JDK 动态代理更高。

1.6 JDK 动态代理 vs CGLIB 动态代理

为了帮助大家更好地选择合适的动态代理技术,我们对 JDK 动态代理和 CGLIB 动态代理进行全面对比:

对比维度JDK 动态代理CGLIB 动态代理
底层实现Java 反射机制ASM 字节码增强技术
目标类要求必须实现接口可以不实现接口,不能是 final 类
代理对象生成方式实现目标类的接口生成目标类的子类
性能较低(反射调用)较高(直接操作字节码)
核心 APIInvocationHandlerProxyMethodInterceptorEnhancer
适用场景目标类实现接口的情况目标类未实现接口的情况
Spring AOP 默认选择目标类有接口时目标类无接口时

✅ 核心结论:在实际开发中,优先使用 JDK 动态代理(符合面向接口编程思想),当目标类没有实现接口时,再使用 CGLIB 动态代理。

1.7 动态代理的实战应用场景

动态代理在 Java 开发中应用广泛,尤其是在框架开发和业务系统设计中,以下是几个典型的实战应用场景。

1.7.1 场景1:基于动态代理的 AOP 日志框架

💡 核心需求:实现一个轻量级的 AOP 日志框架,自动记录所有业务方法的调用日志,包括方法名、参数、执行时间等信息。

代码实现
importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.util.Arrays;/** * AOP 日志框架:JDK 动态代理实现 */// 日志注解:标记需要记录日志的方法public@interfaceLoggable{}// 通用日志调用处理器publicclassLogInvocationHandlerimplementsInvocationHandler{privatefinalObject target;publicLogInvocationHandler(Object target){this.target = target;}@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{// 判断方法是否标记了 @Loggable 注解if(method.isAnnotationPresent(Loggable.class)){long startTime =System.currentTimeMillis();String methodName = method.getName();String params =Arrays.toString(args);// 前置日志System.out.println("[AOP 日志] 方法 "+ methodName +" 开始执行,参数:"+ params);// 执行目标方法Object result = method.invoke(target, args);// 后置日志long endTime =System.currentTimeMillis();System.out.println("[AOP 日志] 方法 "+ methodName +" 执行完毕,耗时:"+(endTime - startTime)+"ms,返回值:"+ result);return result;}else{// 未标记注解的方法,直接执行return method.invoke(target, args);}}// 生成代理对象的工具方法@SuppressWarnings("unchecked")publicstatic<T>TcreateProxy(T target){return(T)Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(),newLogInvocationHandler(target));}}// 业务接口publicinterfaceProductService{@LoggableStringgetProductById(String productId);StringgetProductName(String productId);}// 业务实现类publicclassProductServiceImplimplementsProductService{@OverridepublicStringgetProductById(String productId){// 模拟业务逻辑耗时try{Thread.sleep(100);}catch(InterruptedException e){ e.printStackTrace();}return"产品ID:"+ productId +",名称:Java 编程思想";}@OverridepublicStringgetProductName(String productId){return"Java 编程思想";}}// 测试类publicclassAopLogTest{publicstaticvoidmain(String[] args){ProductService target =newProductServiceImpl();ProductService proxy =LogInvocationHandler.createProxy(target);// 标记 @Loggable 的方法,会记录日志 proxy.getProductById("P1001");// 未标记 @Loggable 的方法,不会记录日志System.out.println("---------------------------"); proxy.getProductName("P1001");}}
运行结果
[AOP 日志] 方法 getProductById 开始执行,参数:[P1001] [AOP 日志] 方法 getProductById 执行完毕,耗时:101ms,返回值:产品ID:P1001,名称:Java 编程思想 --------------------------- 

1.7.2 场景2:基于动态代理的权限校验框架

💡 核心需求:实现一个权限校验框架,在方法执行前自动校验用户的权限,无权限则抛出异常。

代码实现
importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.util.HashSet;importjava.util.Set;/** * 权限校验注解:标记方法所需的权限 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceRequiresPermission{String[]value();}/** * 用户上下文:存储当前登录用户的权限 */publicclassUserContext{privatestaticfinalThreadLocal<Set<String>> userPermissions =newThreadLocal<>();publicstaticvoidsetUserPermissions(String... permissions){Set<String> permissionSet =newHashSet<>();for(String permission : permissions){ permissionSet.add(permission);} userPermissions.set(permissionSet);}publicstaticSet<String>getUserPermissions(){return userPermissions.get();}publicstaticvoidclear(){ userPermissions.remove();}}/** * 权限校验调用处理器 */publicclassPermissionInvocationHandlerimplementsInvocationHandler{privatefinalObject target;publicPermissionInvocationHandler(Object target){this.target = target;}@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{// 判断方法是否需要权限校验if(method.isAnnotationPresent(RequiresPermission.class)){RequiresPermission annotation = method.getAnnotation(RequiresPermission.class);String[] requiredPermissions = annotation.value();Set<String> userPermissions =UserContext.getUserPermissions();// 校验权限boolean hasPermission =false;for(String permission : requiredPermissions){if(userPermissions.contains(permission)){ hasPermission =true;break;}}if(!hasPermission){thrownewSecurityException("权限不足,所需权限:"+String.join(",", requiredPermissions));}}// 执行目标方法return method.invoke(target, args);}// 生成代理对象的工具方法@SuppressWarnings("unchecked")publicstatic<T>TcreateProxy(T target){return(T)Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(),newPermissionInvocationHandler(target));}}// 业务接口publicinterfaceAdminService{@RequiresPermission({"admin:user:add"})voidaddUser(String username);@RequiresPermission({"admin:user:delete"})voiddeleteUser(String userId);}// 业务实现类publicclassAdminServiceImplimplementsAdminService{@OverridepublicvoidaddUser(String username){System.out.println("添加用户成功:"+ username);}@OverridepublicvoiddeleteUser(String userId){System.out.println("删除用户成功:"+ userId);}}// 测试类publicclassPermissionTest{publicstaticvoidmain(String[] args){AdminService target =newAdminServiceImpl();AdminService proxy =PermissionInvocationHandler.createProxy(target);// 测试1:用户拥有 admin:user:add 权限System.out.println("===== 有权限调用 =====");UserContext.setUserPermissions("admin:user:add"); proxy.addUser("王五");// 测试2:用户没有 admin:user:delete 权限System.out.println("\n===== 无权限调用 =====");try{ proxy.deleteUser("1003");}catch(Exception e){System.out.println(e.getMessage());}UserContext.clear();}}
运行结果
===== 有权限调用 ===== 添加用户成功:王五 ===== 无权限调用 ===== 权限不足,所需权限:admin:user:delete 

1.7.3 场景3:Spring AOP 中的动态代理应用

💡 Spring AOP 是动态代理的典型应用,它底层同时支持 JDK 动态代理和 CGLIB 动态代理:

  1. 当目标类实现接口时,Spring AOP 默认使用 JDK 动态代理。
  2. 当目标类没有实现接口时,Spring AOP 自动切换为 CGLIB 动态代理。
  3. 开发者可以通过配置 proxy-target-class="true",强制 Spring AOP 使用 CGLIB 动态代理。

Spring AOP 通过动态代理,实现了横切关注点的统一管理,如日志、事务、权限等功能,大幅提升了代码的复用性和扩展性。

1.8 动态代理的优缺点与最佳实践

1.8.1 动态代理的优点

  1. 解耦核心业务与增强逻辑:将通用功能从核心业务中抽离,实现关注点分离。
  2. 代码复用性高:一套增强逻辑可以复用在多个目标类上,避免重复编码。
  3. 扩展性强:新增增强功能时,只需修改代理逻辑,无需修改目标类代码。
  4. 符合开闭原则:对扩展开放,对修改关闭,是优秀的设计模式实践。

1.8.2 动态代理的缺点

  1. 性能损耗:JDK 动态代理基于反射,存在一定的性能损耗;CGLIB 性能较高,但也比直接调用目标方法慢。
  2. 调试困难:代理对象是运行时生成的,调试时难以跟踪代码执行流程。
  3. 技术门槛高:动态代理涉及反射、字节码操作等高级技术,对开发者的技术水平要求较高。

1.8.3 动态代理的最佳实践

  1. 优先使用 JDK 动态代理:符合面向接口编程思想,代码更具规范性和可维护性。
  2. 合理选择增强时机:对于性能敏感的场景,尽量减少动态代理的使用,或选择 CGLIB 动态代理。
  3. 结合注解使用:通过注解标记需要增强的方法,实现增强逻辑的精准控制。
  4. 使用成熟框架:优先使用 Spring AOP 等成熟框架,避免重复造轮子,提升开发效率。
  5. 做好异常处理:在增强逻辑中处理目标方法的异常,避免异常扩散导致程序崩溃。

1.9 实战案例:基于动态代理的事务管理框架

1.9.1 需求分析

💡 实现一个轻量级的事务管理框架,要求:

  1. 通过注解标记需要事务管理的方法。
  2. 支持事务的自动提交和回滚。
  3. 事务管理逻辑与核心业务逻辑解耦。
  4. 支持 JDK 动态代理和 CGLIB 动态代理。

1.9.2 代码实现

importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importnet.sf.cglib.proxy.Enhancer;importnet.sf.cglib.proxy.MethodInterceptor;importnet.sf.cglib.proxy.MethodProxy;/** * 事务注解:标记需要事务管理的方法 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceTransactional{}/** * 事务管理器:模拟事务的提交和回滚 */publicclassTransactionManager{publicvoidbeginTransaction(){System.out.println("[事务] 开启事务");}publicvoidcommit(){System.out.println("[事务] 提交事务");}publicvoidrollback(){System.out.println("[事务] 回滚事务");}}/** * JDK 动态代理事务处理器 */publicclassJdkTransactionInvocationHandlerimplementsInvocationHandler{privatefinalObject target;privatefinalTransactionManager transactionManager =newTransactionManager();publicJdkTransactionInvocationHandler(Object target){this.target = target;}@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{Object result =null;// 判断方法是否需要事务管理if(method.isAnnotationPresent(Transactional.class)){ transactionManager.beginTransaction();try{ result = method.invoke(target, args); transactionManager.commit();}catch(Exception e){ transactionManager.rollback();throw e;}}else{ result = method.invoke(target, args);}return result;}@SuppressWarnings("unchecked")publicstatic<T>TcreateJdkProxy(T target){return(T)Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(),newJdkTransactionInvocationHandler(target));}}/** * CGLIB 动态代理事务拦截器 */publicclassCglibTransactionInterceptorimplementsMethodInterceptor{privatefinalObject target;privatefinalTransactionManager transactionManager =newTransactionManager();publicCglibTransactionInterceptor(Object target){this.target = target;}@OverridepublicObjectintercept(Object obj,Method method,Object[] args,MethodProxy proxy)throwsThrowable{Object result =null;if(method.isAnnotationPresent(Transactional.class)){ transactionManager.beginTransaction();try{ result = proxy.invokeSuper(obj, args); transactionManager.commit();}catch(Exception e){ transactionManager.rollback();throw e;}}else{ result = proxy.invokeSuper(obj, args);}return result;}@SuppressWarnings("unchecked")publicstatic<T>TcreateCglibProxy(T target){Enhancer enhancer =newEnhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(newCglibTransactionInterceptor(target));return(T) enhancer.create();}}/** * 业务接口 */publicinterfaceAccountService{@Transactionalvoidtransfer(String fromAccount,String toAccount,double amount);}/** * 业务实现类 */publicclassAccountServiceImplimplementsAccountService{@Overridepublicvoidtransfer(String fromAccount,String toAccount,double amount){System.out.println("核心业务:从账户 "+ fromAccount +" 转账 "+ amount +" 到账户 "+ toAccount);// 模拟转账异常if(amount <0){thrownewIllegalArgumentException("转账金额不能为负数");}}}/** * 测试类 */publicclassTransactionTest{publicstaticvoidmain(String[] args){// JDK 动态代理测试System.out.println("===== JDK 动态代理事务测试 =====");AccountService jdkProxy =JdkTransactionInvocationHandler.createJdkProxy(newAccountServiceImpl());// 正常转账 jdkProxy.transfer("A1001","A1002",1000.0);System.out.println("---------------------------");// 异常转账try{ jdkProxy.transfer("A1001","A1002",-500.0);}catch(Exception e){System.out.println("转账失败:"+ e.getMessage());}// CGLIB 动态代理测试(无接口类)System.out.println("\n===== CGLIB 动态代理事务测试 =====");OrderService cglibProxy =CglibTransactionInterceptor.createCglibProxy(newOrderService()); cglibProxy.createOrder("ORDER_20260129");}}

1.9.3 运行结果

===== JDK 动态代理事务测试 ===== [事务] 开启事务 核心业务:从账户 A1001 转账 1000.0 到账户 A1002 [事务] 提交事务 --------------------------- [事务] 开启事务 核心业务:从账户 A1001 转账 -500.0 到账户 A1002 [事务] 回滚事务 转账失败:转账金额不能为负数 ===== CGLIB 动态代理事务测试 ===== [CGLIB 日志] 执行方法:createOrder,参数:ORDER_20260129 核心业务:创建订单 ORDER_20260129 [CGLIB 事务] 方法执行成功,事务提交 

1.9.4 案例总结

✅ 这个事务管理框架综合运用了 JDK 动态代理CGLIB 动态代理 技术,核心亮点如下:

  1. 通过 @Transactional 注解标记需要事务管理的方法,配置简单。
  2. 事务管理逻辑与核心业务逻辑完全解耦,符合关注点分离原则。
  3. 支持两种动态代理方式,适配不同的目标类场景。
  4. 实现了事务的自动提交和回滚,保证了数据的一致性。

1.10 本章总结

  1. 动态代理是代理模式的高级实现,分为 JDK 动态代理CGLIB 动态代理 两类。
  2. JDK 动态代理基于反射机制,要求目标类实现接口;CGLIB 动态代理基于字节码增强,支持无接口类。
  3. 动态代理的核心是 运行时生成代理对象,增强目标方法功能,是实现 AOP 编程的核心技术。
  4. 动态代理广泛应用于日志记录、权限校验、事务管理等场景,是 Spring AOP 等框架的底层实现。
  5. 动态代理的最佳实践是“优先使用 JDK 动态代理,结合注解精准控制,使用成熟框架提升效率”。
  6. 动态代理的本质是解耦核心业务与增强逻辑,提升代码的复用性和扩展性,符合开闭原则。

Read more

C++ 继承入门:从基础概念到默认成员函数,吃透类复用的核心逻辑

C++ 继承入门:从基础概念到默认成员函数,吃透类复用的核心逻辑

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 继承的概念与定义:怎么让类 “复用” 代码? * 1.1 继承的核心概念 * 1.2 继承的定义格式 * 1.3 继承方式与成员访问权限 * 二. 基类与派生类的转换:子类对象能当父类用吗? * 三. 继承中的作用域:同名成员会冲突吗? * 3.1 变量隐藏:同名变量只认子类的 * 3.2 函数隐藏:同名函数只认子类的 * 四. 派生类的默认成员函数:构造、拷贝、析构怎么写? * 4.1 构造函数:先调用父类构造,

By Ne0inhk
C++入门看这一篇就够了——超详细讲解(120000多字详细讲解,涵盖C++大量知识)

C++入门看这一篇就够了——超详细讲解(120000多字详细讲解,涵盖C++大量知识)

目录 一、面向对象的思想 二、类的使用 1.类的构成 2.类的设计 三、对象的基本使用 四、类的构造函数 1.构造函数的作用 2.构造函数的特点 3.默认构造函数 3.1.合成的默认构造函数 3.2.手动定义的默认构造函数 四、自定义的重载构造函数 五、拷贝构造函数 1.手动定义的拷贝构造函数 2.合成的拷贝构造函数 3.什么时候调用拷贝构造函数 六、赋值构造函数 七、析构函数 八、this指针 九、类文件的分离 十、静态数据 1.静态数据成员 2.静态成员函数 十一、

By Ne0inhk
【C++:异常】C++ 异常处理完全指南:从理论到实践,深入理解栈展开与最佳实践

【C++:异常】C++ 异常处理完全指南:从理论到实践,深入理解栈展开与最佳实践

🎬 个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬 艾莉丝的简介: 🎬 艾莉丝的C++专栏简介: 文章目录 * C++学习阶段的三个参考文档 * 1 ~> 异常的概念 * 2 ~> 异常的使用层 * 2.1 异常的抛出和捕获 * 2.2 栈展开 * 2.2.1 理论 * 2.2.2 最佳实践 * 2.3 查找匹配的处理代码 * 2.3.

By Ne0inhk
季节-趋势分解(STL)方法详解

季节-趋势分解(STL)方法详解

季节-趋势分解(STL)方法详解 在分析时间序列数据时,我们经常需要理解数据中隐藏的规律。比如零售商想知道销售额的增长是真实的业务增长还是仅仅是季节性因素,气候学家需要从温度数据中分离出长期变暖趋势和正常的季节变化,这些都需要一种强大的分解方法。STL(Seasonal and Trend decomposition using Loess)正是为此而生的统计方法,它能够将复杂的时间序列数据优雅地分解为三个易于理解的组成部分:趋势、季节性和余项。 数学原理与核心思想 STL的核心思想非常直观:任何时间序列都可以表示为三个加法组成部分的和。用数学公式表达就是: Yν=Tν+Sν+RνY_\nu = T_\nu + S_\nu + R_\nuYν =Tν +Sν +Rν 其中YνY_\nuYν 代表在时间ν\nuν的观测值,TνT_\nuTν 是趋势分量,SνS_\nuSν 是季节分量,RνR_\nuRν 是余项分量。

By Ne0inhk