AOP理解及底层原理

article/2025/9/18 10:22:16

AOP 基础概念

一、概述

AOP (Aspect Oriented Programming)

银行系统的简易取款流程如图:

将方框里的流程合为一个,另外系统还会有一个查询余额流程,如图:

这两个业务有一个共同的验证流程,如图:

为什么会有面向切面编程(AOP)?Java 是面向对象程序设计(OOP)的,但它有一些弊端。AOP 的真正目的是,业务开发,事先只需考虑主流程,而忽略不重要的流程。AOP 可以把这个验证用户的代码提取出来,不放到主流程里去。比如当要为多个不具有担当关系的工具引入一个公共举动,例如日志、权限验证、事务等功能时,只能在每个工具里引用公共举动。如果这样做不便于维护,并且还会有大量相同的代码。AOP 面向方面编程基于IOC,是对 OOP 的有益补充。AOP 是一种思想,不同的厂商或企业可能有不同的实现方式,为了更好的应用 AOP 技术,技术专家们成立了 AOP 联盟来探讨 AOP 的标准化。AOP 联盟定义的 AOP 体系结构把与 AOP 相关的概念大致分为由高到低、从使用到实现的三层关系, AOP 联盟定义的 AOP 体系结构如下图:

在 AOP 联盟定义的 AOP 体系结构下有很多的实现者,例如:AspectJ、JBoss AOP、AspectWerkz、Spring AOP 等。

可以把上面业务方框当块板子,这块板子插入一些控制流程,这些控制流程就可以当成是 AOP 中的一个切面。所以 AOP 的本质是在一系列纵向的业务流程中,把那些相同的子流程提取成一个横向的面。如图二,AOP 相当于把相同的地方连一条横线。

图一

图二

验证用户这个控制流程就成了一个条线,也可以理解成一个切面。这里的切面只插了两三个流程,如果其它流程也需要这个子流程,也可以插到其它地方去。

理解 Spring AOP,先理解代理模式。
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。比如 A 对象要做一件事情,在没有代理前,自己来做;在对 A 代理后,由 A 的代理类 B 来做。代理其实是在原实例前后加了一层处理,这也是 AOP 的初级轮廓。

二、代理模式的原理及实践

代理模式又分为静态代理、动态代理。

1️⃣静态代理原理及实践
说白了,就是在程序运行前就已经存在代理类的字节码文件,代理类和原始类的关系在运行前就已经确定。代码如下:

接口:

public interface IUserDao {void save();void find();
}

目标对象:

class UserDao implements IUserDao{@Overridepublic void save() {System.out.println("模拟:保存用户!");}@Overridepublic void find() {System.out.println("模拟:查询用户");}
}

静态代理特点:
①目标对象必须要实现接口
②代理对象,要实现与目标对象一样的接口

class UserDaoProxy implements IUserDao{//代理对象,需要维护一个目标对象private IUserDao target = new UserDao();@Overridepublic void save() {System.out.println("代理操作: 开启事务...");target.save(); //执行目标对象的方法System.out.println("代理操作:提交事务...");}@Overridepublic void find() {target.find();}
}

静态代理保证了业务类只需要关注逻辑本身,代理对象的一个接口只需要服务于一种类型的对象。如果要代理的方法很多,势必要为每一种方法都进行代理。再者,如果增加一个方法,除了实现类需要实现这个方法外,所有的代理类也要实现此方法,增加了代码的维护成本。那么要如何解决呢?答案是使用动态代理。

2️⃣动态代理原理及实践
动态代理类的源码是在程序运行期间,通过 JVM 反射等机制动态生成。代理类和委托类的关系是运行时才确定的。实例如下:

接口:

public interface IUserDao {void save();void find();
}

目标对象:

class UserDao implements IUserDao{@Overridepublic void save() {System.out.println("模拟: 保存用户!");}@Overridepublic void find() {System.out.println("查询");}
}

动态代理:代理工厂,给多个目标对象生成代理对象

class ProxyFactory {//接收一个目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}//返回对目标对象(target)代理后的对象(proxy)public Object getProxyInstance() {Object proxy = Proxy.newProxyInstance(// 目标对象使用的类加载器target.getClass().getClassLoader(),// 目标对象实现的所有接口 target.getClass().getInterfaces(), // 执行代理对象方法时候触发new InvocationHandler() { @Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// 获取当前执行的方法的方法名String methodName = method.getName();// 方法返回值Object result = null;if ("find".equals(methodName)) {// 直接调用目标对象方法result = method.invoke(target, args);} else {System.out.println("开启事务...");// 执行目标对象方法result = method.invoke(target, args);System.out.println("提交事务...");}return result;}});return proxy;}
}
IUserDao proxy = 
(IUserDao)new ProxyFactory(target).getProxyInstance();

其实是 JDK 动态生成了一个类去实现接口,隐藏了这个过程:

class $jdkProxy implements IUserDao{}

使用 JDK 生成动态代理的前提是目标类必须有实现的接口。如果目标类没有实现接口,就不能使用 JDK 动态代理。CGLIB 代理可以解决这个问题。CGLIB 是以动态生成的子类继承目标的方式实现,在运行期动态的在内存中构建一个子类。CGLIB 使用的前提是目标类不能是 final 修饰的。因为 final 修饰的类不能被继承。

现在,看看 AOP 的定义:面向切面编程,核心原理是使用动态代理模式在方法执行前后或出现异常时加入相关逻辑。

通过定义和前面代码可以发现3点:

  1. AOP 是基于动态代理模式。
  2. AOP 是方法级别的。
  3. AOP 可以分离业务代码和关注点代码(重复代码)。在执行业务代码时,动态的注入关注点代码。切面就是关注点代码形成的类。

三、Spring AOP原理及实战

Spring 框架把 JDK 代理和 CGLIB 代理两种动态代理在底层都集成了进去,开发者无需自己去实现动态生成代理。那么,Spring 是如何生成代理对象的?

  1. 创建容器对象的时候,根据切入点表达式拦截的类,生成代理对象。
  2. 如果目标类有实现接口,使用 JDK 代理;如果目标类没有实现接口,且 class 不为 final 修饰的,则使用 CGLIB 代理;否则不能进行 Spring AOP 编程。然后从容器获取代理后的对象,在运行期植入“切面”类的方法。通过查看 Spring 源码,在 DefaultAopProxyFactory 类中,找到这样一段话。

DefaultAopProxyFactory

手动实现 Spring 的 AOP:
接口:

public interface IUserDao {void save();
}

用于测试 CGLIB 动态代理:

class OrderDao {public void save() {//int i =1/0; 用于测试异常通知System.out.println("保存订单...");}
}

用于测试 JDK 动态代理:

class UserDao implements IUserDao {public void save() {//int i =1/0; 用于测试异常通知System.out.println("保存用户...");}
}

切面类:

class TransactionAop {public void beginTransaction() {System.out.println("[前置通知] 开启事务..");}public void commit() {System.out.println("[后置通知] 提交事务..");}public void afterReturing() {System.out.println("[返回后通知]");}public void afterThrowing() {System.out.println("[异常通知]");}public void arroud(ProceedingJoinPoint pjp) throws Throwable {System.out.println("[环绕前:]");pjp.proceed(); // 执行目标方法System.out.println("[环绕后:]");}
}

Spring 的 XML 配置文件:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- dao实例加入容器 --><bean id="userDao" class="test.spring_aop_anno.UserDao"></bean><!-- dao实例加入容器 --><bean id="orderDao" class="test.spring_aop_anno.OrderDao"></bean><!-- 实例化切面类 --><bean id="transactionAop" class="test.spring_aop_anno.TransactionAop"></bean><!-- Aop相关配置 --><aop:config><!-- 切入点表达式定义 --><aop:pointcut expression="execution(* test.spring_aop_anno.*Dao.*(..))"id="transactionPointcut" /><!-- 切面配置 --><aop:aspect ref="transactionAop"><!-- 【环绕通知】 --><aop:around method="arroud" pointcut-ref="transactionPointcut" /><!-- 【前置通知】 在目标方法之前执行 --><aop:before method="beginTransaction" pointcut-ref="transactionPointcut"/><!-- 【后置通知】 --><aop:after method="commit" pointcut-ref="transactionPointcut" /><!-- 【返回后通知】 --><aop:after-returning method="afterReturing"pointcut-ref="transactionPointcut" /><!-- 异常通知 --><aop:after-throwing method="afterThrowing"pointcut-ref="transactionPointcut" /></aop:aspect></aop:config>
</beans>

四、Spring AOP 应用场景

  1. Spring 声明式事务管理配置;
  2. Controller 层的参数校验;
  3. 使用 Spring AOP 实现 MySQL 数据库读写分离案例分析;
  4. 在执行方法前,判断是否具有权限,Authentication 权限检查;
  5. 对部分函数的调用进行日志记录:监控部分重要函数,若抛出指定的异常,可以以短信或邮件方式通知相关人员;
  6. 信息过滤,页面转发等等功能。
    .
    .
    .
    Caching 缓存
    Context passing 内容传递
    Error handling 错误处理
    Lazy loading 延迟加载
    Debugging  调试
    logging, tracing, profiling and monitoring 日志记录,跟踪,优化,校准
    Performance optimization 性能优化,效率检查
    Persistence  持久化
    Resource pooling 资源池
    Synchronization 同步
    Transactions 事务管理
    另外 Filter 的实现和 struts2 的拦截器的实现都是 AOP 思想的体现。

-------------------------------------------------------------

Spring 不尝试提供最为完善的 AOP 实现,它更侧重于提供一种和 Spring IOC 容器整个的 AOP 实现,用于解决实际的问题,在 Spring 中无缝的整合了 Spring AOP、Spring IOC 和 AspectJ。在使用 Spring AOP 的时候只是简单的配置一下(通过 XML 或注解进行配置),Spring AOP 在内部 ProxyFactory 来创建代理对象,然后调用目标方法。

动态代理或者设计模式很重要!Spring AOP 用到了动态代理,Spring 事务管理用到了动态代理,MyBatis 数据库连接池用到了动态代理,MyBatis 创建 Mapper 用到了动态代理等等!

  1. AOP 面向方面编程基于 IOC,是对 OOP 的有益补充。

  2. AOP 利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,比如日志记录,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

  3. AOP 代表的是一个横向的关系,将“对象”比作一个空心的圆柱体,其中封装的是对象的属性和行为;则面向方面编程的方法,就是将这个圆柱体以切面形式剖开,选择性的提供业务逻辑。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天工的妙手将这些剖开的切面复原,不留痕迹,但完成了效果。

  4. 实现 AOP 的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

  5. Spring 实现 AOP:JDK 动态代理和 CGLIB 代理。JDK 动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是 InvocationHandler 和 Proxy。CGLIB 代理:实现原理类似于 JDK 动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB 是高效的代码生成包,底层是依靠 ASM(开源的 Java 字节码编辑类库)操作字节码实现的,性能比 JDK 强;需要引入包 asm.jar 和 cglib.jar。使用 AspectJ 注入式切面和 @AspectJ 注解驱动的切面实际上底层也是通过动态代理实现的。


http://chatgpt.dhexx.cn/article/gYIKSCIh.shtml

相关文章

Spring AOP原理分析一次看懂

什么是AOP AOP&#xff08;Aspect-OrientedProgramming&#xff0c;面向方面编程&#xff09;&#xff0c;可以说是OOP&#xff08;Object-Oriented Programing&#xff0c;面向对象编程&#xff09;的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构&…

AOP-底层原理

申明&#xff1a;学习笔记整理&#xff0c;内容非原创&#xff0c;仅供参考学习&#xff01;视频详细地址如下&#xff1a; 尚硅谷Spring框架视频教程&#xff08;spring5源码级讲解&#xff09;_哔哩哔哩_bilibili 目录 一、AOP概念 二、AOP底层原理 三、JDK动态代理代码…

Spring AOP原理详解及实例

Spring AOP原理详解及实例 1.Spring AOP简介2.AOP与OOP对比3.AOP使用场景4.AOP相关概念5.AOP实例5.1 基于xml配置方式5.2 基于注解配置方式5.3 AspectJ切点函数 6.可能出现的问题及解决方法6.1 java.lang.IllegalArgumentException: error at :: 0 cant find referenced pointc…

JAVA AOP概念和实现原理 详解

// AOP 概念 1. 什么是AOP&#xff1f; // 面向切面&#xff08;方面&#xff09;编程 //利用AOP可以对业务逻辑的各个部分进行隔离&#xff0c;从而使得业务逻辑各部分之间的耦合度降低&#xff0c;提高程序的可重用性&#xff0c;同时提高了开发的效率 // 不通过修改源代码方…

Spring IOC和AOP 原理彻底搞懂

本博中关于Spring的文章&#xff1a;Spring IOC和AOP原理&#xff0c;Spring事务原理探究&#xff0c;Spring配置文件属性详解&#xff0c;Spring中的代理模式 Spring提供了很多轻量级应用开发实践的工具集合&#xff0c;这些工具集以接口、抽象类、或工具类的形式存在于Sprin…

spring AOP 原理

一、spring注册 AnnotationAwareAspectJAutoProxyCreator 通过EnableAspectJAutoProxy可以看到先把AspectJAutoProxyRegistrar通过Import注册到spring。 AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口&#xff0c;所以就有了将某个bean引入spring 的能力…

Spring的AOP实现原理

本学习笔记将尽可能的将AOP的知识讲解的通俗易懂&#xff0c;先从一个典型的问题出发&#xff0c;引入AOP这个概念&#xff0c;介绍AOP的基本概念&#xff0c;再到Spring中的AOP的实现方案&#xff0c;最后进行一个简单的总结归纳。本学习笔记中不考虑cglib、也不会太关注Sprin…

spring的AOP和IOC的原理

目录 一、spring的ioc与aop原理 二、代理模式&#xff1a; 三、静态代理 四、动态代理 五、实际的操作 六、动态代理的实现&#xff1a; 七、什么是AOP 八、主流的AOP框架&#xff1a; 九、术语&#xff1a; 十、通知的五种类型&#xff1a; 十一、AOP的优点&#x…

spring aop原理

&#x1f345; Java学习路线&#xff1a;搬砖工逆袭Java架构师 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、CSDN哪吒公众号作者✌ 、Java架构师奋斗者&#x1f4aa; &#x1f345; 扫描主页左侧二维码&#xff0c;加入群聊&#xff0c;一起学习、一起进步…

AOP原理

AOP原理 什么是AopAOP的作用AOP的基本概念AOP使用场景AOP原理如何动态修改功能AOP的编程思想AOP面向切面编程操作AOP通知执行的顺序代码执行流程准备工作源码揭开面纱 什么是Aop AOP&#xff08;Aspect Orient Programming&#xff09;也就是面向切面编程&#xff0c;作为面向对…

无法显示页面,因为发生内部服务器错误。

用iis添加网站后&#xff0c;访问域名&#xff0c;显示“无法显示页面&#xff0c;因为发生内部服务器错误。” 之前我将这些文件放在一个Demo文件夹中&#xff0c;把Demo放在test站点下&#xff0c;通过域名访问Demo报错。 我将Demo下的文件直接放在test下&#xff0c;访问成…

遇到“服务器内部错误http500怎么办?

出现500错误的原因是很多的&#xff0c;一般来说都是程序错误导致的&#xff0c;如果程序出错&#xff0c;那么在浏览器内会返回给用户一个友好的错误提示&#xff0c;统一称之为服务器500错误。 解决的方法就是您必须在http中能够正确的获得错误信息&#xff0c;方法为&#x…

500 - 内部服务器错误--解决方案

一般网上的方法是这样的&#xff1a; 一、打开 Internet 信息服务(IIS)管理器。点击出错的站点&#xff0c;并双击右边的ASP图标&#xff0c;如下图所示&#xff1a; 二、展开右侧配置中的“调试属性”&#xff0c;把“将错误发送到浏览器”的值设为 "true"&#xf…

HTTP状态 500 - 内部服务器错误 类型 异常报告,初学servlet遇到的问题

写给自己看&#xff0c;初学记录一下&#xff0c;maven项目中tomcat,Servlet遇到的问题 HTTP状态 500 - 内部服务器错误 类型 异常报告&#xff0c;初学servlet遇到的问题 类似这种报错&#xff0c;在hello world级别的servlet中碰到。 报错分析 大概是说自定义java类在实例…

IIS 配置网站出现500内部服务器错误,显示具体错误信息

1、打开IIS 找到如下图的部分&#xff0c;双击点开 2、点开之后找到如下图部分&#xff0c;点击 3、选择如下图部分&#xff0c;然后点击确定。 4、这个时候页面会出现详细的错误&#xff0c;如果没有出现详细错误&#xff0c;配置如下图部分&#xff0c;不勾选。 5、这时会出现…

Nextcloud 内部服务器错误解决

在部署nextcloud过程中最后登录页面时出现内部服务器错误&#xff0c;心态当时就炸了。 在网上找了各种方案&#xff0c;但是大部分博主都告诉我是/var/lib/php/session/属组的权限问题&#xff0c;或者web目录的权限不对。但是对我这个问题没有用。 我把他们的方案贴出来对你…

IDEA中HTTP500 - 内部服务器错误类型 在 [] 行处理 [/.jsp] 时发生异常情况;java.lang.NoSuchMethodError: com.Bean.Person.setId

问题&#xff1a; HTTP状态 500 - 内部服务器错误 类型 异常报告 消息 在 [65] 行处理 [/pages/el 5/elDataDemo2.jsp] 时发生异常 描述 服务器遇到一个意外的情况&#xff0c;阻止它完成请求。 例外情况 org.apache.jasper.JasperException: 在 [65] 行处理 [/pages/el 5/elDa…

HTTP状态 500 - 内部服务器错误:No converter found for return value of type: class xxx(简单分析及解决)

问题描述 以下内容基于ssm框架&#xff0c;当我们向tomcat服务器发起请求时&#xff0c;出现如下的错误状态提示–500。 Tomcat日志信息&#xff1a; 原因分析&#xff1a; 未找到类型返回值的转换器&#xff1a;类 com.ssm.utils.Msg&#xff0c;使用jackson绑定数据时出现…

阿里云服务器出错500 - 内部服务器错误

阿里云服务器部署并发布成功后&#xff0c;访问该网页时出错&#xff0c;报 500 - 内部服务器错误。 原因&#xff1a;1.http 500内部服务器错误说明IIS服务器无法解析ASP代码&#xff0c;如果你联网还发现找不到服务器就是500错误了. 2.在安装Framework v4.0之后&#xff0c…

HTTP 500 - Internal Server Error 服务器内部错误

php出现如下错误 原因是出现了中文字符 修改后&#xff0c;页面成功访问