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

SpringAOP原理和代理模式详解

1. SpringAOP和代理模式

SpringAOP是建立在代理模式上的,代理模式是它的底层实现机制,而SpringAOP是对代理模式在“面向切面编程”这个领域的高级封装和应用

1.1 理解两个核心概念

  • 代理模式:一种结构设计模式。不想直接操作目标对象,而是创建一个代理对象。客户端调用dialing,代理在调用前后做一些处理(如权限,日志),然后再调用真正的目标,核心是控制访问
  • SpringAOP:一种编程范式,用于将分散在各个业务方法中的横切关注点(如日志、事务、缓存)集中管理,核心是分离关注点

1.2 关系核心:SpringAOP如何利用代理模式

SpringAOP在运行时,并不会修改原始的业务代码。它的做法是:为你指定的目标Bean动态地创建一个代理对象,然后让这个代理对象“替身”区执行工作。具体流程如下:

  1. 定义切面:使用@Aspect或XML定义哪些方法(Pointcut)在什么时候(@Around、@Before、@After......)执行下面额外的逻辑
  2. 创建代理:当Spring容器启动,扫描到你的Bean和切面配置后,它不会直接返回UserService对象本身,按照配置生成代理类
  3. 拦截调用:从容器中获取到实际上是这个“代理对象”,调用userService.saveUser()时调用首先到达代理对象
  4. 执行增强链:代理对象会根据切面配置,依次执行@Before方法 、saveUser()本体、@After方法等
  5. 委托给目标:最终,代理对象会通过方法调用(反射或直接调用)区执行原始的UserService的svaeUser()方法

结论:SpringAOP中的“切面”、“通知”、“切入点”等高级概念,最终都是通过“代理对象”这个具体的技术手段实现的。没有代理模式,SpringAOP无从谈起

2. 代理模式

2.1 静态代理

代理类在编译期就已经确定了,手动编写,每个主题需要单独编写一个代理类

优点:简单,容易理解

缺点:当接口增加方法时,代理类和真实类都要进行修改

2.2 动态代理

代理类在运行时动态生成,无需为每个类手动编写代理

2.2.1JDK动态代理

要求:目标对象必须实现至少一个接口

实现:

  1. 定义一个接口及其实现类
  2. 自定义InvocationHandler并重写invoke方法,在invoke方法中我们会调用目标方法并自定义一些处理逻辑
  3. 通过Proxy.newProxyInstance(ClassLoder loder,Class<?>[] interfaces,InvocationHandler h)方法擦混关键代理对象
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Service { void execute(); } class RealService implements Service { public void execute() { System.out.println("执行真实业务"); } } class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } 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; } } // 使用 Service real = new RealService(); Service proxy = (Service) Proxy.newProxyInstance( real.getClass().getClassLoader(), real.getClass().getInterfaces(), new MyInvocationHandler(real) ); proxy.execute();

1. InvocationHandler

InvocationHandler接口是java动态代理的关键接口之一,它定义了一个单一的方法invoke(),用于处理被代理对象的方法调用

public interface InvocationHandler { /** * 参数说明 * proxy:代理对象 * method:代理对象需要实现的⽅法,即其中需要重写的⽅法 * args:method所对应⽅法的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }

通过实现InvocationHandler接口,可以对被代理对象的方法进行功能增强

2. Proxy

Proxy类中使用频率最高的方法:newProxyInstance(),这个方法主要用来生成一个代理对象

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws InvocationHandler h){ // 代码省略...... }

这个方法一共有三个参数:

Loader:类加载器,用于加载代理对象

interfaces:被代理类实现的一些接口(这个参数的第一也决定了JDK动态代理只能代理实现了接口的一些类)

h:实现了InvocationHandler接口的对象

2.2.2 CGLIB动态代理

要求:目标类无需实现接口类,但不能是final类,方法也不能是final

实现:

  1. 定义一个类
  2. 自定义MethodInterceptor并重写intercept方法,intercept用于增强目标方法,和JDK中的invoke方法类似
  3. 通过Enhancer类的create()创建代理类
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; class RealService { public void execute() { System.out.println("真实业务"); } } class MyMethodInterceptor implements MethodInterceptor { 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; } } // 使用 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RealService.class); enhancer.setCallback(new MyMethodInterceptor()); RealService proxy = (RealService) enhancer.create(); proxy.execute();

1.MethodInterceptor

MethodInterceptor和JDK动态代理中的InvocationHandler类似,它只定义了一个方法intercept,用于增强目的方法

2.Enhancer.create()

用来生成一个代理对象

public static Object create(Class type, Callback callback) { //...代码省略 }

type:被代理类的类型(类或接口)

callback:自定义方法拦截器MethodInterceptor

http://www.cnnetsun.cn/news/2819812.html

相关文章:

  • SpeakCoach
  • 实测揭秘:WPS双进程备份机制,内存占用真的高吗?手把手教你手动清理驻留进程
  • VMware网络感叹号?别急着重装!手把手教你修复VMnet1/VMnet8驱动代码31错误
  • 扫描阅卷机支持哪些格式的试卷?
  • 2、K8S网络概述
  • x64汇编案例5
  • SysConfig Device Support 笔记
  • VC6环境下内存直载DLL的完整可运行工程包(含源码、编译成品与测试模块)
  • ToxiTwitch:基于混合模型的Twitch实时聊天毒性检测
  • 新闻语义处理流水线:面向金融NLP的结构化解码与时序锚定
  • AI动态简报之商业洞察篇(2026.06.07)
  • 电机控制工程师必看:手把手教你配置TMS320F280049的SDFM模块进行电流采样
  • 【个人博客—山东大学项目实训——古诗词与文章智能创作助学平台(六)】
  • 生产级机器学习服务的三大支柱:可观测性、弹性和契约
  • AI实战第5篇:Python+DeepSeek智能简历优化器,HR看了直呼专业
  • 跨境支付业务流程
  • Sqribble文档自动化系统:模板驱动的结构化出版流水线
  • 别再只用System.out.printf了!Java格式化数字的三种姿势,从基础到实战一次讲透
  • ROS 2进阶:深入理解rosdep与package.xml的依赖关系,打造可复用的机器人软件包
  • Vue3 + Baidu Map API 实战:手把手教你实现一个带搜索和自定义弹窗的店铺地图
  • 多维聚合中的数据变形:从GROUP BY到高维视图的工程实践
  • 手机存储速度翻倍的秘密:一文看懂UFS 2.2里的M-PHY物理层(附避坑指南)
  • 告别黑盒:用dotPeek和Symbol Server在VS里一步步调试Newtonsoft.Json源码
  • AT24C02不止是存储:聊聊I2C总线上的设备地址与多机通信那点事
  • 你的V-SLAM为啥飘?从重投影误差的角度聊聊后端优化的那些坑
  • Logisim新手避坑指南:复用器、译码器、优先编码器到底怎么用?
  • 从IEBus到AVC-LAN:拆解丰田老车机里的“古董”通信协议与数据帧
  • 给CANoe DLL加个“耳朵”:手把手教你用Visual Studio 2019编写并调试回调函数
  • 从监控面板到服务治理:手把手教你用Dubbo-Admin管理微服务(附Docker部署彩蛋)
  • AD9831输出信号不过零点?一个电容或变压器轻松搞定(附Multisim仿真)