Spring中AOP的实现原理
一、什么是 AOP ?
AOP(Aspect-Oriented Programming,面向方面编程),对 OOP(Object-Oriented Programming,面向对象编程)
- 【OOP与AOP】
- 概念
- AOP(Aspect-Oriented Programming,面向方面编程)
- OOP(Object-Oriented Programming,面向对象编程)
- 方向
- OOP 定义从上到下的关系
- AOP 定义从左到右的关系
- 概念
- 【两个部分】
- 核心关注点
- 业务处理的主要流程
- 横切关注点
- 与业务主要流程关系不大的部分
- 经常发生在核心关注点的多处,而各处都是基本相似的功能
- 如权限认证、日志、事务处理
- 核心关注点
二、AOP 使用场景
1、AOP框架种类
- AspectJ
- JBoss AOP
- Spring AOP
2、使用 AOP 场景
- 性能监控:在方法调用前后记录调用事件,方法执行太长或超时报警。
- 缓存代理:缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。
- 软件破解:使用AOP修改软件的验证类的判断逻辑。
- 记录日志:在方法执行前后记录系统日志。
- 工作流系统:工作流系统需要将业务代码和流畅引擎代码混合在一起执行,那么可以使用 AOP 将其分离,并动态挂载业务。
- 权限验证:方法执行前验证是否有权限执行当前方法,没有则抛出没有权限执行异常,由业务代码捕获。
3、传统编码与AOP区别
三、核心概念
【术语】:
- 切面(Aspect):
一个关注点的模块化,这个关注点可能会横切多个对象。
事务管理是 J2EE 应用中一个关于横切关注点的很好列子。
在 Spring AOP 中,切面可以使用基于模式或者基于 @Aspect 注解的方式来实现。
- 连接点(Joinpoint):
在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。
在 Spring AOP 中,一个连接点总是表示一个方法的执行。
- 切入点(Pointcut):
匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如:当执行某个特定名称的方法时)。
切入点表达式如何和连接点匹配是 AOP 的核心:Spring 缺省使用 Aspect 切入点语法。
- 引入(Introduction):
用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))
Spring 允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,可以使用引入来使一个 bean 实现 isModified 接口,以便简化缓存机制。
- 目标对象(Target Object):
被一个或者多个切面所通知的对象,也被称为通知(advised)对象。
既然 Spring AOP 是通过运行时代理实现的。这个对象永远是一个被代理(proxied)对象。
- AOP 代理(AOP Proxy):
AOP 框架创建的对象,用来实现切面契约(例如,通知方法执行等等)。
在 Spring 中,AOP 代理可以是 JDK 动态代理或者 CGLIB 代理。
- 织入(Weaving):
把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用 AspectJ 编译器),类加载时和运行时完成。Spring 和其他纯 Java AOP 框架一样,在运行时完成织入。
- 通知(Advice):
在切面的某个特定的连接点上执行的动作。其中包括“around”、“before” 和 “after” 等不同类型的通知。
许多 AOP 框架(包括 Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
【通知类型】
- 前置通知(Before advice):
@Before
在某连接点之前执行的通知,但这个通知不能阻止了连接点之前的执行流程(除非它抛出一个异常)。
- 后置通知(After returning advice):
@After
在某连接点正常完成后执行的通知,例如,一个方法么有抛出任何异常,正常返回。
- 异常通知(After throwing advice):
@After-returning
在方法抛出异常退出时执行的通知。
- 最终通知(After(finally)advice):
@After-throwing
当某连接点退出的时候执行的通知(不论是正常退出还是异常退出);
- 环绕通知(Around advice):
@Around
包围一个连接点的通知,如方法调用,这是最强大的一种通知类型。
三、简单例子
1、基于注解的方式
@Aspectj
public class TransactionDemo {@Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")public void point() { //... }@Before(value="point()")public void before() {System.out.println("transaction begin");}@AfterReturning(value = "point()")public void after() {System.out.println("transaction commit");}@Around("point()")public void around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("transaction begin");joinPoint.proceed();System.out.println("transaction commit");}
}
在 applicationContext.xml 中配置:
<aop:aspectj-autoproxy /><bean id="transactionDemo" class="com.yangxin.core.transaction.TransactionDemo" />
2、基于 XML 的方式
<aop:config><aop:aspect ref="log"><aop:pointcutexpression="(execution(* spring.ch3.topic1.Chief.*(..)))"id="chiefPointCut" /><aop:before method="washOven" pointcut-ref="chiefPointCut" /><aop:before method="prepare" pointcut-ref="chiefPointCut" /><aop:after method="after" pointcut-ref="chiefPointCut" /></aop:aspect>
</aop:config>
四、Spring AOP 原理
AOP 代理其实是由 AOP 框架动态生成的一个对象,该对象可作为目标对象使用。
AOP 代理包含了目标对象的全部方法,但 AOP 代理中的方法与目标对象的方法存在差异:AOP 方法在特定切入点添加了增强处理,并回调了目标对象的方法。
Spring 的 AOP 代理由 Spring 的 IoC 容器负责生成、管理,其依赖关系也由 IoC 容器负责管理。因此,AOP 代理可以直接使用容器中的其他 Bean 实例作为目标,这种关系可由 IoC 容器的依赖注入提供。
aop开发时,其中需要参与开发的只有 3 个部分:
- 定义普通业务组件。
- 定义切入点,一个切入点可能横切多个业务组件。
- 定义增强处理,增强处理就是在 AOP 框架为普通业务组件织入的处理动作。
五、两种动态代理方式
Spring默认采取的动态代理机制实现AOP,当动态代理不可用时(代理类无接口)会使用CGlib机制。
Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。
1、JDK 动态代理
- JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
- Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
2、CGLib动态代理
- CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLib封装了asm,可以再运行期动态生成新的class。和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理。
六、补充实例
package springMVCmybatis.com.my.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.springframework.core.annotation.Order;@Aspect
@Order(3)
public class MyAopTest {@Pointcut("execution(* springMVCmybatis.addController.addEmp(..))")private void pointCutMethod() { //... }@Pointcut("execution(* springMVCmybatis.com.my.aop.UserServiceImp.*(..))") private void testAOP() { //... }/*** 声明前置通知 ,JoinPont是srpring提供的静态变量,* 通过joinPoint参数可以获得目标方法的类名,方法参数,方法名等信息,这个参数可有可无。*/@Before("pointCutMethod() || testAOP()") public void doBefore(JoinPoint joinPoint) { System.out.println("@Before:开始添加--order=3"); } /*** 声明后置通知 ,如果result的类型与proceed执行的方法返回的参数类型不匹配那么就不会执行这个方法*/@AfterReturning(pointcut = "pointCutMethod() || testAOP()", returning = "result") public void doAfterReturning(String result) { System.out.println("@AfterReturning:后置通知--order=3"); System.out.println("---" + result + "---"); } /*** 声明例外通知 */@AfterThrowing(pointcut = "pointCutMethod() || testAOP()", throwing = "e") public void doAfterThrowing(Exception e) { System.out.println("@AfterThrowing:例外通知--order=3"); System.out.println(e.getMessage()); }/*** 声明最终通知*/@After("pointCutMethod() || testAOP()") public void doAfter() { System.out.println("@After:最终通知--order=3"); } /*** 声明环绕通知* 参数必须是ProceedingJoinPoint,通过该对象的proceed()方法来执行目标函数,* proceed()的返回值就是环绕通知的返回值,proceedingJoinPoint是个接口,* implement JoinPoint,所以也可以获得目标函数的类名,方法名等参数。*/@Around("pointCutMethod() || testAOP()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("@Around:进入方法---环绕通知--order=3"); Object o = pjp.proceed(); System.out.println("@Around:退出方法---环绕通知--order=3"); return o; }
}
七、切点表达式
1、方法签名表达式
execution(<修饰符模式>?<返回类型模式><方法所在类的完全限定名称模式>(<参数模式>)<异常模式>?)
execution(modifiers-pattern? ret-type-pattern fully-qualified-class-name (param-pattern) throws-pattern?)
对比方法的定义来记忆,一个java方法的全部定义方式可以表示成下面的方式:
public String springMVCmybatic.com.my.aop.UserServiceImp(String a, int b) throw Exception{}
- modifier-pattern?:表示方法的修饰符,可有可无;对应的就是 public
- ret-type-pattern:表示方法的返回值;对应的就是 String
- fully-qualified-class-name 方法所在类的完全限定名称;对应的就是 springMVCmybatic.com.my.aop.UserServiceImp
- param-pattern:表示方法的参数;对应的就是 String a, int b
- throws-pattern:表示方法抛出的异常,可有可无;对应的就是 throw Exception
2、&&,||,!(表达式之间可以采用与,或,非的方式来过滤。)
@Around("pointCutMethod() || testAOP()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("@Around:进入方法---环绕通知"); Object o = pjp.proceed(); System.out.println("@Around:退出方法---环绕通知"); return o;
}
八、多个切点的执行顺序
上面的例子中,定义了order=3,重新创建一个切面,定义order=6,执行的结果是:
@Around:进入方法---环绕通知--order=3
@Before:开始添加--order=3
@Around:进入方法---环绕通知--order=6
@Before:开始添加--order=6
============执行业务方法findUser,查找的用户是:张三=============
@Around:退出方法---环绕通知--order=6
@After:最终通知--order=6
@AfterReturning:后置通知--order=6
---张三---
@Around:退出方法---环绕通知--order=3
@After:最终通知--order=3
@AfterReturning:后置通知--order=3
---张三---@Around:进入方法---环绕通知--order=3
@Before:开始添加--order=3
@Around:进入方法---环绕通知--order=6
@Before:开始添加--order=6
============执行业务方法addUser=============
@After:最终通知--order=6
@AfterThrowing:例外通知--order=6
null
@After:最终通知--order=3
@AfterThrowing:例外通知--order=3
null
从结果中可以看出order越小越先执行,执行完了之后就order越小就越后推出。总结为下面的图:
spring
Spring中AOP的实现原理相关推荐
- Spring 容器AOP的实现原理——动态代理
本文来自极客学院 Spring 容器AOP的实现原理--动态代理 之前写了一篇关于IOC的博客--<Spring容器IOC解析及简单实现>,今天再来聊聊AOP.大家都知道Spring的两大 ...
- spring中aop事务
文章目录 事务 为什要用到Spring中AOP事务 事物的特性 ACID 事务并发问题 事务的隔离级别 spring事务管理 事务操作 事务操作对象 spring管理事务的属性介绍 spring管理事 ...
- Spring中AOP源码剖析
Spring中AOP源码剖析 关键词 aop的增强发生在后置处理器中(没有循环依赖) 最终增强是通过 递归调用 ,层层增强 一.环境准备 1.1 bean和接口 public class AopBea ...
- spring中AOP(面向切面编程)
spring中AOP(面向切面编程) 面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是spring框架中的一个重要内容 ...
- 动态代理以及对应Spring中AOP源码分析
AOP(面向切面编程)在Spring中是被广泛应用的(例如日志,事务,权限等),而它的基本原理便是动态代理. 我们知道动态代理有两种:基于JDK的动态代理以及基于CGlib动态代理.以下是两种动态代理 ...
- Spring的AOP与IOC原理
一.IOC(Inversion of Control):控制反转 传统模式下使用类的方法与属性,我们需要new出这个类的对象,然后使用对象进行方法调用,这种方法耦合度极高,为了降低耦合度,Spring ...
- 【Spring】AOP底层实现原理 —— 动态代理类的创建(JDK、CGlib)、工厂加工原始对象
一.AOP概念 AOP (Aspect Oriented Programing) 面向切面编程 = Spring动态代理开发 以切面为基本单位的程序开发,通过切面间的彼此协同,相互调用,完成程序的构建 ...
- Spring中AOP相关的API及源码解析,原来AOP是这样子的
前言 之所以写这么一篇文章主要是因为下篇文章将结束Spring启动整个流程的分析,从解析配置到创建对象再到属性注入最后再将创建好的对象初始化成为一个真正意义上的Bean.因为下篇文章会涉及到AOP,所 ...
- spring中AOP动态代理的两种方式
AOP动态代理的两种方式 Spring AOP动态代理的方式(spring的AOP默认是JDK Proxy) 浅谈这两种动态代理 JDK的动态代理,需要有实现接口 动态代理--JDK Proxy ⚫ ...
- Spring中AOP的使用
问题:什么是AOP? 答:AOP基本概念:Aspect-Oriented Programming,面向方面编程的简称,Aspect是一种新的模块化机制,用来描述分散在对象.类或方法中的横切关注点(cr ...
最新文章
- wps底纹去不掉_汽车异味总是去不掉?建议车主试试这5个办法,空气清新又好闻...
- javax.swing.jFrame
- bzoj 4711 小奇挖矿 ——“承诺”类树形dp
- Mysql允许外网接入
- flask mysql 版本_flask 数据库字段类型
- Spring Boot笔记-@ComponentScan初步解析
- TextView实现歌词同步《IT蓝豹》
- 计算机维护系统Win8PE,U盘启动计算机维护系统
- OpenGL采样贴图显示不出来
- 使用Python写登录京东商城购物,加入购物车的脚本
- plSQL表格、视图名称右击,再点击view查看详情,突然找不到了咋办?
- WIN10和WIN11修改C盘用户文件夹名称
- 幼儿园网络图怎么绘制_幼儿园主题网络图的绘制要注意什么
- Could not load the Qt platform plugin “xcb“ 问题解决
- 大数据专业应该怎么学习
- 【英语阅读】纽约时报 | 马云正式退休,但仍将影响阿里帝国
- 复旦2021计算机考研分数线,2021复旦大学考研录取分数线公布|附详情
- 五种JavaScript富文本编辑器,总有一款适合你
- 云卷云舒:2022 数据库总结从Gartner到IDC
- 更改计算机图标,Win7如何修改桌面图标
热门文章
- tmsf28335的启动步骤
- 580刷590bios_RX580 2048sp刷vbios降为RX570 用上黑苹果美滋滋
- 2021计算机专业考研科目,2021北京航空航天大学计算机考研科目
- 计算机专业数学建模结课论文,数学建模结课论文3000字论文
- JAVEWEB 过滤器Filter的实现
- 解决谷歌浏览器最新版本CORS跨域问题
- We‘re sorry but XX doesn‘t work properly without JavaScript enabled. Please enable it to continue
- fiddler和wireshark对比
- 【Linux】文件系统及软硬连接
- 五、OpenCV-python 之图像处理(Ⅲ)——傅里叶变换