一篇文搞懂《AOP面向切面编程,DevOps生命周期
表达式:
execution(public double ArithmeticCalculator.*(double, double))
含义:
参数类型为double,double类型的方法
这里还有一个定位最模糊的表达式:
execution("* *(…)")
表示任意包下任意类的任意方法,但是这个表达式千万别写,哈哈,不然你每一个执行的方法都会有通知方法执行的!
同时,在AspectJ中,切入点表达式可以通过 “&&”、“||”、“!”等操作符结合起来。
如:
execution (* .add(int,…)) || execution( *.sub(int,…))
表示任意类中第一个参数为int类型的add方法或sub方法
3、注解实践
现在我们已经知道了注解和切入点表达式的使用,那么接下来就是进行实践了,
对于切入点表达式,我们可以直接在注解中使用“”写在其中,还可以在@AfterReturning注解和@AfterThrowing注解中将切入点赋值给pointcut属性,但是在其他的注解中没有pointcut这个参数。
将切入点表达式应用到实际的切面类中如下:
@Aspect //切面注解@Component //其他业务层public class LogUtli {// 方法执行开始,表示目标方法是com.spring.inpl包下的任意类的任意以两个int为参数,返回int类型参数的方法@Before("execution(public int com.spring.inpl.*.*(int, int))")public static void LogStart(JoinPoint joinPoint) {System.out.println("通知记录开始...");}// 方法正常执行完之后/*** 在程序正常执行完之后如果有返回值,我们可以对这个返回值进行接收* returning用来接收方法的返回值* */@AfterReturning(pointcut="public int com.spring.inpl.*.*(int, int)",returning="result")public static void LogReturn(JoinPoint joinPoint,Object result) {System.out.println("【" + joinPoint.getSignature().getName() + "】程序方法执行完毕了...结果是:" + result);}}
以上只是一个最简单的通知方法,但是在实际的使用过程中我们可能会将多个通知方法切入到同一个目标方法上去,比如同一个目标方法上既有前置通知、又有异常通知和后置通知。
但是这样我们也只是在目标方法执行时切入了一些通知方法,那么我们能不能在通知方法中获取到执行的目标方法的一些信息呢?当然是可以的。
4、JoinPoint获取方法信息
在这里我们就可以使用JoinPoint接口来获取到目标方法的信息,如方法的返回值、方法名、参数类型等。
如我们在方法执行开始前,获取到该目标方法的方法名和输入的参数并输出。
// 方法执行开始@Before("execution(public int com.spring.inpl.*.*(int, int))")public static void LogStart(JoinPoint joinPoint) {Object[] args = joinPoint.getArgs(); //获取到参数信息Signature signature = joinPoint.getSignature(); //获取到方法签名String name = signature.getName(); //获取到方法名System.out.println("【" + name + "】记录开始...执行参数:" + Arrays.asList(args));}
5、接收方法的返回值和异常信息
对于有些目标方法在执行完之后可能会有返回值,或者方法中途异常抛出,那么对于这些情况,我们应该如何获取到这些信息呢?
首先我们来获取当方法执行完之后获取返回值,
在这里我们可以使用@AfterReturning注解,该注解表示的通知方法是在目标方法正常执行完之后执行的。
在返回通知中,只要将returning属性添加到@AfterReturning注解中,就可以访问连接点的返回值。
该属性的值即为用来传入返回值的参数名称,但是注意必须在通知方法的签名中添加一个同名参数。
在运行时Spring AOP会通过这个参数传递返回值,由于我们可能不知道返回值的类型,所以一般将返回值的类型设置为Object型。
与此同时,原始的切点表达式需要出现在pointcut属性中,
如下所示:
// 方法正常执行完之后/*** 在程序正常执行完之后如果有返回值,我们可以对这个返回值进行接收* returning用来接收方法的返回值* */@AfterReturning(pointcut="public int com.spring.inpl.*.*(int, int)",returning="result")public static void LogReturn(JoinPoint joinPoint,Object result) {System.out.println("【" + joinPoint.getSignature().getName() + "】程序方法执行完毕了...结果是:" + result);}
对于接收异常信息,方法其实是一样的。
我们需要将throwing属性添加到@AfterThrowing注解中,也可以访问连接点抛出的异常。Throwable是所有错误和异常类的顶级父类,所以在异常通知方法可以捕获到任何错误和异常。
如果只对某种特殊的异常类型感兴趣,可以将参数声明为其他异常的参数类型。然后通知就只在抛出这个类型及其子类的异常时才被执行。
实例如下:
// 异常抛出时/*** 在执行方法想要抛出异常的时候,可以使用throwing在注解中进行接收,* 其中value指明执行的全方法名* throwing指明返回的错误信息* */@AfterThrowing(pointcut="public int com.spring.inpl.*.*(int, int)",throwing="e")public static void LogThowing(JoinPoint joinPoint,Object e) {System.out.println("【" + joinPoint.getSignature().getName() +"】发现异常信息...,异常信息是:" + e);}
6、环绕通知
我们在上面介绍通知注解的时候,大家应该也看到了其实还有一个很重要的通知——环绕通知,
环绕通知是所有通知类型中功能最为强大的,能够全面地控制连接点,甚至可以控制是否执行连接点。
对于环绕通知来说,连接点的参数类型必须是ProceedingJoinPoint。它是 JoinPoint的子接口,允许控制何时执行,是否执行连接点。
在环绕通知中需要明确调用ProceedingJoinPoint的proceed()方法来执行被代理的方法。如果忘记这样做就会导致通知被执行了,但目标方法没有被执行。这就意味着我们需要在方法中传入参数ProceedingJoinPoint来接收方法的各种信息。
注意:
环绕通知的方法需要返回目标方法执行之后的结果,即调用 joinPoint.proceed();的返回值,否则会出现空指针异常。
具体使用可以看下面这个实例:
/*** 环绕通知方法* 使用注解@Around()* 需要在方法中传入参数proceedingJoinPoint 来接收方法的各种信息* 使用环绕通知时需要使用proceed方法来执行方法* 同时需要将值进行返回,环绕方法会将需要执行的方法进行放行* ********************************************** @throws Throwable * */@Around("public int com.spring.inpl.*.*(int, int)")public Object MyAround(ProceedingJoinPoint pjp) throws Throwable {// 获取到目标方法内部的参数Object[] args = pjp.getArgs();System.out.println("【方法执行前】");// 获取到目标方法的签名Signature signature = pjp.getSignature();String name = signature.getName();Object proceed = null;try {// 进行方法的执行proceed = pjp.proceed();System.out.println("方法返回时");} catch (Exception e) {System.out.println("方法异常时" + e);}finally{System.out.println("后置方法");}//将方法执行的返回值返回return proceed;}
7、通知注解的执行顺序
那么现在这五种通知注解的使用方法都已经介绍完了,
我们来总结一下这几个通知注解都在同一个目标方法中时的一个执行顺序。
在正常情况下执行:
@Before(前置通知)—>@After(后置通知)---->@AfterReturning(返回通知)
在异常情况下执行:
@Before(前置通知)—>@After(后置通知)---->@AfterThrowing(异常通知)
当普通通知和环绕通知同时执行时:
执行顺序是:
环绕前置----普通前置----环绕返回/异常----环绕后置----普通后置----普通返回/异常
8、重用切入点定义
对于上面的通知注解,我们都是在每一个通知注解上都定义了一遍切入点表达式,
但是试想一个问题,如果我们不想给这个方法设置通知方法了,或者我们想要将这些通知方法切入到另一个目标方法,那么我们岂不是要一个一个的更改注解中的切入点表达式吗?这样也太麻烦了吧?
所以spring就想到了一个办法,重用切入点表达式。
也就是说将这些会重复使用的切入点表达式用一个方法来表示,那么我们的通知注解只需要调用这个使用了该切入点表达式的方法即可实现和之前一样的效果,这样的话,我们即使想要更改切入点表达式的接入方法,也不用一个一个的去通知注解上修改了。
获取可重用的切入点表达式的方法是:
随便定义一个void的无实现的方法
为方法添加注解@Pointcut()
在注解中加入抽取出来的可重用的切入点表达式
使用value属性将方法加入到对应的切面函数的注解中
完整实例如下:
@Aspect //切面注解@Component //其他业务层public class LogUtli {/*** 定义切入点表达式的可重用方法* */@Pointcut("execution(public int com.spring.inpl.MyMathCalculator.*(int, int))")public void MyCanChongYong() {}// 方法执行开始@Before("MyCanChongYong()")public static void LogStart(JoinPoint joinPoint) {Object[] args = joinPoint.getArgs(); //获取到参数信息Signature signature = joinPoint.getSignature(); //获取到方法签名String name = signature.getName(); //获取到方法名System.out.println("【" + name + "】记录开始...执行参数:" + Arrays.asList(args));}// 方法正常执行完之后/*** 在程序正常执行完之后如果有返回值,我们可以对这个返回值进行接收* returning用来接收方法的返回值* */@AfterReturning(value="MyCanChongYong()",returning="result")public static void LogReturn(JoinPoint joinPoint,Object result) {System.out.println("【" + joinPoint.getSignature().getName() + "】程序方法执行完毕了...结果是:" + result);}// 异常抛出时/*** 在执行方法想要抛出异常的时候,可以使用throwing在注解中进行接收,* 其中value指明执行的全方法名* throwing指明返回的错误信息* */@AfterThrowing(value="MyCanChongYong()",throwing="e")public static void LogThowing(JoinPoint joinPoint,Object e) {System.out.println("【" + joinPoint.getSignature().getName() +"】发现异常信息...,异常信息是:" + e);}// 结束得出结果@After(value = "execution(public int com.spring.inpl.MyMathCalculator.add(int, int))")public static void LogEnd(JoinPoint joinPoint) {System.out.println("【" + joinPoint.getSignature().getName() +"】执行结束");}/*** 环绕通知方法* @throws Throwable * */@Around("MyCanChongYong()")public Object MyAround(ProceedingJoinPoint pjp) throws Throwable {// 获取到目标方法内部的参数Object[] args = pjp.getArgs();System.out.println("【方法执行前】");// 获取到目标方法的签名Signature signature = pjp.getSignature();String name = signature.getName();Object proceed = null;try {// 进行方法的执行proceed = pjp.proceed();System.out.println("方法返回时");} catch (Exception e) {System.out.println("方法异常时" + e);}finally{System.out.println("后置方法");}//将方法执行的返回值返回return proceed;}}
以上就是使用AspectJ注解实现AOP切面的全部过程了,
在这里还有一点特别有意思的规定提醒大家,就是当你有多个切面类时,切面类的执行顺序是按照类名的首字符先后来执行的(不区分大小写)。
接下来我来和大家讲解一下实现AOP切面编程的另一种方法——基于XML配置的AOP实现,
四、基于XML配置的AOP实现
==================================================================================
基于XML配置的AOP切面顾名思义就是摒弃了注解的使用,转而在IOC容器中配置切面类,这种声明是基于aop名称空间中的XML元素来完成的,
在bean配置文件中,所有的Spring AOP配置都必须定义在< aop:config>元素内部。对于每个切面而言,都要创建一个< aop:aspect>元素来为具体的切面实现引用后端bean实例。
切面bean必须有一个标识符,供< aop:aspect>元素引用。
所以我们在bean的配置文件中首先应该先将所需切面类加入到IOC容器中去,之后在aop的元素标签中进行配置。我们在使用注解进行开发的时候,五种通知注解以及切入点表达式这些在xml文件中同样是可以配置出来的。
1、声明切入点
切入点使用
< aop:pointcut>元素声明。
切入点必须定义在< aop:aspect>元素下,或者直接定义在< aop:config>元素下。
定义在< aop:aspect>元素下:只对当前切面有效
定义在< aop:config>元素下:对所有切面都有效
基于XML的AOP配置不允许在切入点表达式中用名称引用其他切入点。
2、声明通知
在aop名称空间中,每种通知类型都对应一个特定的XML元素。
通知元素需要使用< pointcut-ref>来引用切入点,或用< pointcut>直接嵌入切入点表达式。
method属性指定切面类中通知方法的名称
具体使用可以看下面这里实例:
最后
由于篇幅有限,这里就不一一罗列了,20道常见面试题(含答案)+21条MySQL性能调优经验小编已整理成Word文档或PDF文档,点击这里免费下载
还有更多面试复习笔记分享如下
切入点必须定义在< aop:aspect>元素下,或者直接定义在< aop:config>元素下。
定义在< aop:aspect>元素下:只对当前切面有效
定义在< aop:config>元素下:对所有切面都有效
基于XML的AOP配置不允许在切入点表达式中用名称引用其他切入点。
2、声明通知
在aop名称空间中,每种通知类型都对应一个特定的XML元素。
通知元素需要使用< pointcut-ref>来引用切入点,或用< pointcut>直接嵌入切入点表达式。
method属性指定切面类中通知方法的名称
具体使用可以看下面这里实例:
最后
由于篇幅有限,这里就不一一罗列了,20道常见面试题(含答案)+21条MySQL性能调优经验小编已整理成Word文档或PDF文档,点击这里免费下载
[外链图片转存中…(img-pb5RmVX8-1628606663161)]
还有更多面试复习笔记分享如下
[外链图片转存中…(img-KsYPf9fi-1628606663164)]
一篇文搞懂《AOP面向切面编程,DevOps生命周期相关推荐
- Springboot 一文搞懂AOP面向切面编程
Springboot AOP面向切面编程 AOP简介 AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构. 作用:在不惊动原始设计的 ...
- java aop面向切面编程
最近一直在学java的spring boot,一直没有弄明白aop面向切面编程是什么意思.看到一篇文章写得很清楚,终于弄明白了,原来跟python的装饰器一样的效果.http://www.cnblog ...
- AOP(面向切面编程)大概了解一下
前言 上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程. 正文 1. 概述 在软件业, ...
- python aop编程_学习笔记: AOP面向切面编程和C#多种实现
AOP:面向切面编程 编程思想 OOP:一切皆对象,对象交互组成功能,功能叠加组成模块,模块叠加组成系统 类--砖头 系统--房子 类--细胞 系统--人 面向对象是非常适合做大型 ...
- AOP—面向切面编程
前言 上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程. 正文 概述 在软件业,AOP ...
- 【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行原理分析
文章目录 一.查看使用 AspectJ 后生成的 Class 字节码类 二.AspectJ 的本质 一.查看使用 AspectJ 后生成的 Class 字节码类 在 Android Studio 中查 ...
- 【AOP 面向切面编程】Android Studio 中配置 AspectJ ( 下载并配置AS中 jar 包 | 配置 Gradle 和 Gradle 插件版本 | 配置 Gradle 构建脚本 )
文章目录 一.AspectJ 下载 二.拷贝 aspectjrt.jar 到 Android Studio 三.配置 Gradle 和 Gradle 插件版本 四.配置 Gradle 构建脚本 一.A ...
- 【AOP 面向切面编程】AOP 简介 ( AspectJ 简介 | AspectJ 下载 )
文章目录 一.AOP 简介 二.AspectJ 简介 三.AspectJ 下载 一.AOP 简介 AOP 是 Aspect Oriented Programming 的缩写 , 面向切面编程 ; 利用 ...
- 切面是异步还是同步操作‘_Autofac的AOP面向切面编程研究
什么是AOP: 我的理解是 把系统性的编程工作封装起来 =>我给这个取个名字叫 "Aspect",然后通过AOP技术把它切进我们的业务逻辑代码 => "业务& ...
- Javascript aop(面向切面编程)之around(环绕)
Aop又叫面向切面编程,其中"通知"是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在j ...
最新文章
- 缓存核心知识小抄,面试必备,赶紧收藏!
- 访问 IIS 元数据库失败解决问题的方法
- tensorflow 风格迁移二
- python实现数据恢复_使用sklearn进行对数据标准化、归一化以及将数据还原的方法...
- socket closed是什么意思_socket请求
- NOI.AC-积木【堆】
- python 小说 云_小说python操作PLC
- 最短路径——dj+floyd+spfa(hdu2544)
- arduino舵机代码_Arduino如何同时使用多个串口
- 计算机学硕缩招,专硕扩招、学硕缩招!又有院校初试科目改了!本周这些院校发布最新消息!...
- 20个Flutter实例视频教程-01节底部导航栏和切换效果的制作-1
- jsp mysql超市管理_基于WEB的小型超市管理系统的设计与实现(JSP,MySQL)
- 计算机组成原理——指令分析
- 官方JwPlayer去水印步骤
- c语言步长,(转+原创)c语言那些细节之a+1和a+1的区别 ,指针的步长问题。
- app打开QQ与陌生人聊天
- HDMI 之 HPD .
- 如何免费将excel表格转换成Word文档?
- 利用python绘制简易词云图(使用jieba进行中文分词)
- 校招群面及专业面技巧总结(适用产品等非技术岗)
热门文章
- 【MAC技巧】 MAC下两款免费的风扇调节工具
- 中专计算机教师天涯,天涯里有教职高或中专的教师吗?你们现在过得好吗~~
- linux mint18 win8主题,Ubuntu/Linux Mint用上仿Win7/Win8主题
- java struts validate_重写ActionForm中的Validate()方法
- FSViewer 一款功能强大的看图软件
- [笔记分享] [Camera] msm8926 camera hal 流程小结
- 机器之心 Pro·AI 趋势先锋 Insight 榜单发布
- 城通网盘仿蓝奏网盘源码|字母哥网盘|+搭建教程
- u深度重装系统详细教程_u深度重置用户密码操作步骤
- 网页导出Word几种方法简介