Spring AOP 实现原理

Spring——AOP原理及流程详解 基于5.3.9 版本的Spring源码,对AOP原理及流程详解,AOP是在Bean生成流程中什么位置介入处理的?各个通知方法又是怎么组装的?AOP真的只是动态代理这么简单吗? 阅读详情

关于 Aspect 切面

在 AOP 的使用中,Aspect 切面由 Pointcut 和 Advice 组成,但是没有写到如何进行切入的,这就是本篇博客所介绍的 “ Proxy ” ,即 代理 。


Proxy 代理

首先,当在 bean 的生命周期中,spring在给 bean 执行初始化后置,即方法postProcessAfterInitialization()的时候(一般情况下是这样,如果是出现了bean循环依赖,会在实例化结束后即调用了createBeanInstance()反射方法之后依赖注入之前进行生成 Proxy),去进行 AOP 的生成。

因为初始化后置方法是每生成一个 Bean 就要执行一次这个方法,正好对应了 AOP 的需求,即为每一个需要 AOP 的 Bean 进行 面向切面编程 。

而就是这个时候 AOP 就会生成 Bean 的代理对象 Proxy 。


关于Proxy的实现方式

这里运用到了一个技术叫做 “动态代理” 。而对于动态代理的实现方式有两种,分别为 JDK 代理 和 CGLIB 代理 。
为了方便理解,这里先用 “静态代理” 做演示。

1. 静态代理

定义接口

  • 首先先写一个接口。
java

// 定义接口类 UserService

public interface UserService {

void saveUser(String username);

}

接口实现

  • 再写一个实现类去实现此接口。
java

// 接口实现类 UserServiceImpl

public class UserServiceImpl implements UserService {

@Override

public void saveUser(String username) {

System.out.println("【真实业务】正在保存用户: " + username);

}

}

静态代理类

  • 这里是静态代理的重点,静态代理类创建。
java

// 静态代理类 UserServiceStaticProxy

public class UserServiceStaticProxy implements UserService {

private UserService target;

// 拿到目标对象

public UserServiceStaticProxy(UserService target) {

this.target = target;

}

// 运用重写的操作进行业务增强

@Override

public void saveUser(String username) {

// 前置增强

System.out.println("静态代理-前置操作...");

// 调用目标方法

target.saveUser(username);

// 后置增强

System.out.println("静态代理-后置操作...");

}

}

实际使用

  • 使用静态代理进行工作
java

// 实际的使用

public class StaticProxyTest {

public static void main(String[] args) {

// 创建一个实现类为目标类 target

UserService target = new UserServiceImpl();

// 创建一个代理对象 proxy 进行对 target 的代理

UserService proxy = new UserServiceStaticProxy(target);

// 执行代理的方法(这是重写增强后的方法)

proxy.saveUser("张三");

}

}


2. 动态代理 之 JDK代理

定义接口

  • 同上写一个接口。
java

// 定义接口类 UserService

public interface UserService {

void saveUser(String username);

}

接口实现

  • 也是写一个实现类去实现此接口。
java

// 接口实现类 UserServiceImpl

public class UserServiceImpl implements UserService {

@Override

public void saveUser(String username) {

System.out.println("真实业务..." + username);

}

}

动态代理(重点)

java

// 实现动态代理

public class JdkProxyHandler implements InvocationHandler {

private Object target;

public Object bind(Object target) {

this.target = target;

return Proxy.newProxyInstance(

target.getClass().getClassLoader(),

target.getClass().getInterfaces(),

this);

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 前置增强

System.out.println("JDK代理-前置方法调用: " + method.getName());

// 核心:通过反射调用目标方法

Object result = method.invoke(target, args);

// 后置增强

System.out.println("JDK代理-后置方法调用");

// 返回原方法的执行结果

return result;

}

}

  • 首先对于方法 invoke() ,这是一种特殊的方法:每当调用代理 proxy 的时候,proxy 会自动执行invoke()方法,而这也是所谓proxy代理的核心作用。
    invoke() 的参数 proxy 指的是本身, method 指的是原对象的方法, arg 表是以列表的形式存放的原对象的方法所需的参数。
  • 对于方法 Proxy.newProxyInstance :这里的 proxy 是一种 “伪造的实现类” ,通过 getClassLoader() 和 getInterfaces() 将目标的 “类的加载” 和 “接口实现” 传给了 proxy 。并通过处理器 new JdkProxyHandler(target) 的处理从而使 proxy 成功 “伪装” 成了实现了对应接口的目标类,变成了原方法的 “替身” 。

实际使用

java

// 实际的使用

public class JdkProxyTest {

public static void main(String[] args) {

JdkProxyHandler jdkProxyHandler = new JdkProxyHandler();

// 用接口类去接收这个 proxy 代理类

UserService userService = (UserService)jdkProxyHandler.bind(new UserServiceImpl())

userService.saveUser("张三");

}

}

  • 对于代码 UserService userService = (UserService)jdkProxyHandler.bind(new UserServiceImpl()) ,它将原实现类 new UserServiceImpl() 通过 bind 方法进行包装成一个proxy代理类,然后用接口类实例 UserService userService 接收。

问题来了: 那为什么不用原来的实现类接收,而是用接口类接收呢??

答: proxy相当于这个接口的实现类,而原目标类也是这个接口的实现类。
虽然proxy是增强了目标类,但是和目标类本质上不一样!所以相当于现在是有两个实现类,都实现了同一个接口,所以才用接口接收,以免报错。


3. 动态代理 之 CGLIB代理

定义接口

  • CGLIB 其实不强依赖接口。
java

// 不需要接口哦

普通类实现

  • CGLIB 的强大之处在于,即使只有一个普通的类,没有接口,它也能进行代理。
java

体验AI代码助手

代码解读

复制代码

// 普通类 UserServiceImpl (不需要 implements UserService 去实现接口)

public class UserServiceImpl {

public void saveUser(String username) {

System.out.println("真实业务...正在保存用户: " + username);

}

}

动态代理(重点)

java

// 实现动态代理

public class CglibProxyHandler implements MethodInterceptor {

// 创建代理对象的核心方法

public Object bind(Class<?> targetClass) {

// 1. 创建增强器(代理工厂)

Enhancer enhancer = new Enhancer();

// 2. 设置目标类(也就是父类)

enhancer.setSuperclass(targetClass);

// 3. 设置回调(也就是拦截器本身)

enhancer.setCallback(this);

// 4. 创建并返回代理对象

return enhancer.create();

}

@Override

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

// 前置增强

System.out.println("CGLIB代理-前置方法调用: " + method.getName());

// 通过 MethodProxy 调用父类(目标类)的方法

// 注意:这里使用 invokeSuper 而不是 method.invoke,效率更高

Object result = methodProxy.invokeSuper(proxy, args);

// 后置增强

System.out.println("CGLIB代理-后置方法调用");

return result;

}

}

  • 关于 enhancer :这个所谓的 “增强器” 其实就是一个 “代理工厂”,可以用 enhancer.create() 生成代理对象 proxy 。
  • 关于 enhancer.setCallback() 方法,参数为 this 。这个方法叫做 “回调” ,是为了将下面的 intercept 增强的方法传递给代理工厂 enhancer ,等到需要生成代理对象 proxy 的时候,工厂会自动将这个 intercept 增强方法塞进代理对象 proxy 中。
  • 对于方法 enhancer.create():这里的 proxy 是一种 “伪造的子类” ,即将目标类作为父类,让代理类 proxy 去继承目标类。CGLIB 会在内存中动态生成了一个 继承自目标类 的新类( 就是这个 proxy )。它通过重写父类的所有非 final 方法,并在方法中织入我们的增强逻辑,从而变成了原方法的“替身”。
  • 对于方法 intercept(),这是 CGLIB 的拦截核心。每当调用代理对象的方法时,会执行此方法。 proxy:指的是 CGLIB 生成的代理对象本身。 method:指的是 目标类的方法。 args:指的是 方法参数。 methodProxy:这是 CGLIB 特有的参数,它是对目标方法的快速代理,比 JDK 的反射调用性能更好。

实际使用

java

// 实际的使用

public class CglibProxyTest {

public static void main(String[] args) {

CglibProxyHandler cglibProxyHandler = new CglibProxyHandler();

// 用原来的类去接收这个 proxy 代理类

UserServiceImpl userService = (UserServiceImpl) cglibProxyHandler.bind(UserServiceImpl.class);

userService.saveUser("张三");

}

}

  • 对于代码 UserServiceImpl userService = (UserServiceImpl) cglibProxyHandler.bind(UserServiceImpl.class),它将原类 UserServiceImpl.class 通过 bind 方法包装成一个 proxy 代理类,然后用 原类实例 UserServiceImpl userService 接收。
    问题来了:为什么 CGLIB 可以用原来的类接收,而 JDK 代理不行呢??

答:因为 CGLIB 采用的是继承的方式。
CGLIB 生成的代理类是目标类的子类,而目标类是父类。
在 Java 中,子类对象是可以赋值给父类引用的(多态)。所以,代理对象(子类)可以直接被当作目标类(父类)来使用,自然就可以用原来的类去接收了。


关于动态代理使用

在 Spring 框架中,AOP 代理的创建是由 AopProxyFactory 决定的。

Spring 默认遵循以下策略:

  • 如果目标对象实现了接口:默认使用 JDK 动态代理。
    建议:在这种情况下,业务类应当实现接口,这是 Java 设计模式的最佳实践。
  • 如果目标对象没有实现接口:必须使用 CGLIB。
  • 强制使用 CGLIB:
    即使目标对象实现了接口,你也可以通过配置强制 Spring 使用 CGLIB ,例如:
    • 在 XML 中设置 <aop:config proxy-target-class="true"/>
    • 在注解配置中开启 proxyTargetClass=true 。

注意:使用 CGLIB 时,目标类不能是 final 的,且需要被代理的方法也不能是 final 或 private 的(因为子类无法重写这些方法)。

Spring AOP功能实现 一、AOP的基本概念: 1、什么是aop:AOP(Aspect Oriented Programming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。在不改变原有的逻辑的基础上,增加一些额外的功能。代理也是这个功能,读写分离也能用aop来做。AOP可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层. 阅读详情

相关推荐

Spring中AOP实现原理

AOP实现原理 核心概念,使用场景

qq_14886109的博客 968

Spring AOP的实现原理

Spring AOP的底层实现原理及详细介绍以及适配器和常用通知的使用

weixin_74268571的博客 3757

Spring AOP —— 详解、实现原理、简单demo

AOP 就是面向切面的编程, 是一种思想,是对某一类事情的集中处理。

CYK_byte的博客 3525

springAop实现原理

springAop实现原理

ChenJin_2的博客 2658

AutoLISP 学习 (一)

AutoLISP基本语法结构、语法 以括号组成表达式,左右括号一定要成对,单、双引号也要成对,例如: (defun c:hello() (princ "\nHello world!") (prin1) ) 表达式格式:(函数名 操作数 操作数 …),例如: (setq p1 (list 0 0)) (setq p2 (list 10 10)) (setq p3 (list 20 20)) ;;; CAD中画直线,经过p1 p2 p3 (command "LINE" p1 p2 p3 ""

m0_54575622的博客 2122

RoboMaster机甲大师赛备赛:如何用STM32+CAN总线精准控制四个大疆3508电机?

本文详细介绍了在RoboMaster机甲大师赛中,如何利用STM32和CAN总线技术精准控制四台大疆3508电机。从硬件架构设计、多电机ID分配、数据解析到同步控制算法,全面解析了构建高响应、低延迟底盘驱动系统的关键技术,助力参赛队伍提升机器人运动性能。

weixin_28684825的博客 133

Spring AOP实现原理

Spring AOP 的核心是动态代理和AOP 代理工厂。1. 解析切面(Aspect) → 2. 创建代理工厂(ProxyFactory) → 3. 生成代理对象(JDK / CGLIB) → 4. 方法调用时拦截并执行切面逻辑特性Spring AOP 实现实现方式动态代理(JDK / CGLIB)代理生成时机Bean 初始化后(通知类型执行顺序按拦截器链顺序执行限制仅支持方法拦截,不支持构造器、字段代理失效场景。

红血哥 1376

高温环境下RS485通信故障分析与MOS管解决方案

RS485通信作为工业控制领域的基础总线技术,其可靠性直接影响系统稳定性。在高温等恶劣环境下,传统三极管开关电路会因温度特性导致通信故障。通过分析三极管Ube电压随温度变化的特性,揭示了电路失效的物理原理。相比之下,MOS管作为电压控制型器件,具有温度稳定性好、功耗低等优势,更适合工业环境应用。本文通过一个发动机舱内RS485通信故障的实际案例,详细对比了三极管与MOS管在高温环境下的性能差异,并给出了具体的电路改进方案。该案例对工业通信接口设计具有普遍参考价值,特别适用于需要应对高温、振动等挑战性环境的硬

weixin_42612405的博客 406

Spring AOP的工作原理和实现方式

AOP是Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

A_aspectJ的博客 2201

Android11,无障碍服务模拟多手势使用dispatchGesture时总是onCancelled

AccessibilityService的dispatchGesture去模拟多手势,总是onCancelled的一种解决办法

m0_49953943的博客 2102

fpga在线升级 linux_仅5000行Verilog代码、可在FPGA上跑轻量级Linux系统的RISC-V内核

本文发布于www.hackster.io,由东京理工大学的计算机学院开发,专用于教学与加速用(苏老师也一直认为这是RISC-V当前的主要方向)。目前市场上开源的RISC-V内核已经很多,但很少有公开的RISC-V计算系统是非常轻型且能跑Linux系统的。这一款RISC-V内核就可以运行在FPGA上,用Verilog编写的,需要很少硬件的资源就能跑起来,所以可以运行在一个低成本的FPGA上。来看一下...

weixin_34083807的博客 1867

Spring AOP原理底层实现详解

Spring AOP原理底层实现详解。

大户影视的博客 1973

增程式永磁电机发电系统电压环二自由度控制器设计

本论文主要研究增程式永磁电机发电系统的电压环二自由度控制器设计。该系统采用二自由度控制策略,通过精确调节电压环和电流环,显著提高系统的动态响应性能和稳态稳定性。基于SVPWM(空间矢量脉宽调制)技术,本研究设计的电压环控制器能够在负载突变和外部扰动的情况下,快速恢复并保持电压稳定,从而满足增程式永磁电机发电系统对电压精度和稳定性的高要求。仿真分析表明,所设计的控制器在不同工况下展现出良好的电压稳定性、较短的响应时间和较低的稳态误差,能够有效抑制电压波动并提高系统的鲁棒性。实验结果表明,控制器在维持高效能和高

weixin_44553616的博客 897

Spring AOP 的实现及原理

spring aop 的实现及原理

qq_71360748的博客 935

秋叶ComfyUI整合包使用FRP实现公网访问教程 ComfyUI内网穿透 秋叶整合包

最近在做 ComfyUI 的实验时,我发现很多小伙伴都遇到一个问题:本地启动的 ComfyUI 服务只能在本地访问,想要通过公网远程访问,就必须借助来实现。作为一名前端开发工程师,我花了点时间把 ComfyUI 启动器和 FRP 配置整合了一下,今天就分享给大家。本文适合已经了解。需要注意的是 穿透到公网的话任何人都能访问 为了安全建议看我另一篇帖子加上密码验证 防止恶意攻击。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1347

记录一次Spring Framework 漏洞修复的过程

摘要:针对Spring Boot 2.6.13项目在阿里云漏洞扫描中发现的Spring Framework目录遍历漏洞(CVE-2024-38819),首先分析了漏洞成因,确认5.3.23版本存在风险。解决方案包括升级Spring Boot至2.7.18(对应Spring Framework 5.3.41)或6.0+版本,但后者需JDK17支持。临时方案通过配置HttpFirewall限制特殊字符,最终借助阿里云防护服务暂时解决问题。建议长期解决方案仍需升级至安全版本(Spring Boot 6.1.14或

极客栈 1486

Spring的AOP实现原理

客户端代码 -> 调用被代理Bean的方法 -> 实际调用的是动态生成的代理对象 (JDK Proxy或CGLIB子类) -> 代理对象查找匹配该方法的通知链 -> 创建MethodInvocation包装本次调用 -> 驱动MethodInvocation.proceed() -> 按顺序执行拦截器链中的 MethodInterceptor (对应各种通知) -> 最终在链中调用原始目标对象的方法 -> 结果/异常沿链返回 -> 代理对象将结果返回给客户端。​:AOP 联盟定义的拦截器接口。

YangChingyuk的博客 872

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Spring AOP实现原理简介

AOP联盟标准AOP联盟将AOP体系分为三层,从三层结构可以看出,AOP实现方式有很多种,包括反射、元数据处理、程序处理、拦截器处理等,通过本节学习,你就会看到Spring AOP的实现使用的是Java语言本身的特性,即Java Proxy代理类、拦截器技术实现。AOP简介概念切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。连接点(Joinpoint)...

wyl6019的博客 7万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Spring aop的实现原理

简介   前段时间写的java设计模式--代理模式,最近在看Spring Aop的时候,觉得于代理模式应该有密切的联系,于是决定了解下Spring Aop的实现原理。   说起AOP就不得不说下OOP了,OOP中引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。但是,如果我们需要为部分对象引入公共部分的时候,OOP就会引入大量重复的代码。例如:日志功能。   AO...

一起进步的博客 278

spring中AOP实现的原理

AOP:全称是Aspect Oriented Programming即:面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。简单的说:它就是把我们程序中重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有的方法的增强。

haha_66666的博客 353

Spring AOP ① 实现原理

AOP的实现原理分3个阶段收集切面生成代理使用代理对象。

weixin_37711738的博客 1272

spring AOP的实现原理

Spring aop的实现原理 简介   前段时间写的java设计模式–代理模式,最近在看Spring Aop的时候,觉得于代理模式应该有密切的联系,于是决定了解下Spring Aop的实现原理。 说起AOP就不得不说下OOP了,OOP中引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。但是,如果我们需要为部分对象引入公共部分的时候,OOP就会引入大量重复的代码。例如...

qq_43757153的博客 447
上一篇: 1700页,卷S人的 《八股文》PDF手册,涨薪跳槽拿高薪就靠它了
下一篇: 凭借这份国内最新最全Java八股文(终极版),我成功入职字节T2-2
退休的汤姆
博客等级 码龄7年 1657粉丝 1051原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值