【Spring】一文带你吃透AOP面向切面编程技术(下篇)

个人主页: 几分醉意的CSDN博客_传送门
上节我们介绍了什么是AOP、Aspectj框架的前置通知@Before传送门,这篇文章将继续详解Aspectj框架的其它注解。
文章目录
- 💖Aspectj框架介绍
- ✨JoinPoint通知方法的参数
- ✨后置通知@AfterReturning
- ✨环绕通知@Around
- ✨异常通知@AfterTrowing
- ✨@Pointcut定义和管理切入点注解
- ✨总结
- 💖投票传送门(欢迎伙伴们投票)
💖Aspectj框架介绍
AOP技术思想的实现:使用框架实现AOP。实现AOP的框架有很多。有名的两个
1. Spring:Spring框架实现AOP思想中的部分功能。Spring框架实现AOP的操作比较繁琐,笨重。
2. Aspectj:独立的框架,专门做AOp的,功能最强大的。属于Eclipse。
而我下面主要介绍的就是Aspectj框架来实现Aop,Aspectj框架可以使用注解和xml配置文件两种方式实现AOP。
✨JoinPoint通知方法的参数
切面类中的通知方法,可以有参数,但是必须是JoinPoint。
JoinPoint: 表示正在执行的业务方法。 相当于反射中 Method
使用要求:必须是参数列表的第一个
作用:获取方法执行时的信息,例如方法名称, 方法的参数集合
下面我们直接实战,注意下面用的是上一节的前置通知的业务接口和实现类。
切面类
@Aspect
public class MyAspect {@Before(value = "execution(* *..SomeServiceImpl.do*(..) )")public void myBefore2(JoinPoint jp){//获取方法的定义System.out.println("前置通知中,获取目标方法的定义:"+ jp.getSignature());System.out.println("前置通知中,获取方法的名称"+jp.getSignature().getName());//获取方法执行时的参数Object[] args = jp.getArgs(); //返回的是一个数组 里面存放的是所有参数for (Object arg : args) {System.out.println("前置通知,获取方法的参数是"+arg);}//切面的代码。System.out.println("===前置通知,切面的功能,在目标方法之前先执行==:"+new Date());System.out.println("");}}
测试
@Testpublic void test(){//如果没有加入代理的处理:// 1)目标方法执行时,没有切面功能的。// 2) service对象没有被改变//加入代理的处理:// 1)目标方法执行时,有切面功能的。// 2) service对象是改变后的 代理对象 com.sun.proxy.$Proxy8String s = "applicationContext.xml";ApplicationContext ctx = new ClassPathXmlApplicationContext(s);SomeService service = (SomeService)ctx.getBean("someService");service.doSome("ll" , 22);}
//JoinPoint:哪个目标对象方法执行时,它就代表哪个方法//例如这里doSome执行时,它就代表doSome,然后可以获取这个方法的信息
执行结果:

拓展:

✨后置通知@AfterReturning
* @AfterReturning:后置通知* 属性:value 切入点表达式* returning 自定义的变量,表示目标方法的返回值的。* 自定义变量名称必须和通知方法的形参名一样* 位置:在方法的上面** 特点:* 1.在目标方法之后,执行的。* 2.能获取到目标方法的执行结果。* 3.不会影响目标方法的执行** 方法的参数:* Object res: 表示目标方法的返回值,使用res接收doOther的调用结果。* Object res= doOther();** 后置通知的执行顺序* Object res = SomeServiceImpl.doOther(..); 先执行业务方法* myAfterReturning(res); 在执行后置通知** 思考:* 1 doOther方法返回是String ,Integer ,Long等基本类型,* 在后置通知中,修改返回值, 是不会影响目标方法的最后调用结果的。* 2 doOther返回的结果是对象类型,例如Student。* 在后置通知方法中,修改这个Student对象的属性值,会不会影响最后调用结果?*
下面通过举例的方式,带大家理解后置通知。
首先业务接口添加doOther方法,然后实现它的实现类
public interface SomeService {void doSome(String name,Integer age);String doOther(String name,Integer age);
}
public class SomeServiceImpl implements SomeService {@Overridepublic void doSome(String name, Integer age) {System.out.println("业务方法doSome(),创建商品订单");}@Overridepublic String doOther(String name, Integer age) {System.out.println("执行业务方法doOther,处理库存");return "abcd";}
}
创建切面类
@Aspect
public class MyAspect {//定义方法,表示切面的具体功能/*后置通知方法的定义1)方法是public2)方法是void3)方法名称自定义4)方法有参数,推荐使用Object类型*/@AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",returning = "res")public void myAfterReturning(JoinPoint jp , Object res){System.out.println("后置通知,在目标方法之后,执行的。能拿到执行结果:"+res);//修改目标方法的返回值if(res != null){res = "HELLO Aspectj";}System.out.println("后置通知,修改res后"+res);}
}
测试:
@Testpublic void test02(){String config="applicationContext.xml";ApplicationContext ctx = new ClassPathXmlApplicationContext(config);SomeService service = (SomeService) ctx.getBean("someService");String ret = service.doOther("zhangsan", 20);System.out.println("test02中调用目标方法的结果:"+ret);}
执行结果:

✨环绕通知@Around
特点介绍:







* @Around:环绕通知* 属性:value 切入点表达式* 位置:在方法定义的上面** 返回值:Object ,表示调用目标方法希望得到执行结果(不一定是目标方法自己的返回值)* 参数: ProceedingJoinPoint, 相当于反射中 Method。* 作用:执行目标方法的,等于Method.invoke()** public interface ProceedingJoinPoint extends JoinPoint {}** 特点:* 1.在目标方法的前和后都能增强功能* 2.控制目标方法是否执行* 3.修改目标方法的执行结果。*
@Aspect
public class MyAspect {//定义方法,表示切面的具体功能/*环绕置通知方法的定义1)方法是public2)方法是必须有返回值, 推荐使用Object类型3)方法名称自定义4)方法必须有ProceedingJoinPoint参数,*/@Around("execution(* *..SomeServiceImpl.doFirst(..))")public Object myAround(ProceedingJoinPoint pjp) throws Throwable {Object methodReturn = null;System.out.println("执行了环绕通知,在目标方法之前,输出日志时间=="+ new Date());//执行目标方法 ProceedingJoinPoint,表示doFirstmethodReturn = pjp.proceed();//method.invoke(),表示执行doFirst()方法本身if( methodReturn != null){methodReturn ="环绕通知中,修改目标方法原来的执行结果";}System.out.println("环绕通知,在目标方法之后,增加了事务提交功能");//return "HelloAround,不是目标方法的执行结果";//返回目标方法执行结果。没有修改的。return methodReturn;}}
测试:
@Testpublic void test02(){String config="applicationContext.xml";ApplicationContext ctx = new ClassPathXmlApplicationContext(config);SomeService service = (SomeService) ctx.getBean("someService");String ret = service.doFirst("zhangsan");System.out.println("ret调用目标方法的结果:"+ret);}
执行结果:

✨异常通知@AfterTrowing
业务接口和实现类:
public interface SomeService {void doSecond(String name);
}
@Service
public class SomeServiceImpl implements SomeService {@Overridepublic void doSecond(String name) {System.out.println("执行业务方法doSecond,处理库存"+(10/0));}
}
切面类:
@Aspect
public class MyAspect {//定义方法,表示切面的具体功能/*异常通知方法的定义1)方法是public2)方法是没有返回值。是void3)方法名称自定义4)方法有参数是Exception*//*** @AfterThrowing:异常通知* 属性: value 切入点表达式* throwing 自定义变量,表示目标方法抛出的异常。* 变量名必须和通知方法的形参名一样* 位置:在方法的上面* 特点:* 1. 在目标方法抛出异常后执行的, 没有异常不执行* 2. 能获取到目标方法的异常信息。* 3. 不是异常处理程序。可以得到发生异常的通知, 可以发送邮件,短信通知开发人员。* 看做是目标方法的监控程序。** 异常通知的执行* try{* SomeServiceImpl.doSecond(..)* }catch(Exceptoin e){* myAfterThrowing(e);* }*/@AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))",throwing = "ex")public void myAfterThrowing(Exception ex){System.out.println("异常通知,在目标方法抛出异常时执行的,异常原因是:"+ex.getMessage());/*异常发生可以做:1.记录异常的时间,位置,等信息。2.发送邮件,短信,通知开发人员*/}}
测试:
@Testpublic void test01(){String config="applicationContext.xml";ApplicationContext ctx = new ClassPathXmlApplicationContext(config);SomeService service = (SomeService) ctx.getBean("someService");service.doSecond("lisi");}
执行结果:
✨ 最终通知@After
业务接口和实现类:
public interface SomeService {void doThird();
}
@Service
public class SomeServiceImpl implements SomeService {@Overridepublic void doThird() {System.out.println("执行了业务方法doThird()");}
}
切面类:
@Aspect
public class MyAspect {//定义方法,表示切面的具体功能/*最终通知方法的定义1)方法是public2)方法是没有返回值。是void3)方法名称自定义4)方法没有参数*//*** @After:最终通知* 属性: value 切入点表达式* 位置: 在方法的上面* 特点:* 1. 在目标方法之后执行的。* 2. 总是会被执行。* 3. 可以用来做程序最后的收尾工作。例如清除临时数据,变量。 清理内存** 最终通知* try{* SomeServiceImpl.doThird(..)* }finally{* myAfter()* }*/@After(value = "execution(* *..SomeServiceImpl.doThird(..))")public void myAfter(){System.out.println("最终通知,总是会被执行的");}}
测试:
@Testpublic void test01(){String config="applicationContext.xml";ApplicationContext ctx = new ClassPathXmlApplicationContext(config);SomeService service = (SomeService) ctx.getBean("someService");service.doThird();}
执行结果:

✨@Pointcut定义和管理切入点注解
@Aspect
public class MyAspect {@Before(value = "mypt()")public void myBefore(){System.out.println("前置通知,在目标方法之前先执行的");}@After(value = "mypt()")public void myAfter(){System.out.println("最终通知,总是会被执行的");}/*** @Pointcut: 定义和管理切入点,不是通知注解。* 属性: value 切入点表达式* 位置: 在一个自定义方法的上面, 这个方法看做是切入点表达式的别名。* 其他的通知注解中,可以使用方法名称,就表示使用这个切入点表达式了*/@Pointcut("execution(* *..SomeServiceImpl.doThird(..))")private void mypt(){//无需代码}
}
✨总结
AOP是一种动态的技术思想,目的是实现业务功能和非业务功能的解耦合。业务功能是独立的模块,其他功能也是独立的模块。例如事务功能,日志等等。让这些事务,日志功能是可以被复用的。
当目标方法需要一些功能时,可以在不修改,不能修改源代码的情况下,使用aop技术在程序执行期间,生成代理对象,通过代理执行业务方法,同时增加功能。
💖投票传送门(欢迎伙伴们投票)
相关文章:
【Spring】一文带你吃透AOP面向切面编程技术(下篇)
个人主页: 几分醉意的CSDN博客_传送门 上节我们介绍了什么是AOP、Aspectj框架的前置通知Before传送门,这篇文章将继续详解Aspectj框架的其它注解。 文章目录💖Aspectj框架介绍✨JoinPoint通知方法的参数✨后置通知AfterReturning✨环绕通知Ar…...
【java】Spring Boot --40 个 Spring Boot 常用注解(建议收藏)
本文目录一、Spring Web MVC 注解Spring Web MVC 注解RequestMappingRequestBodyGetMappingPostMappingPutMappingDeleteMappingPatchMappingControllerAdviceResponseBodyExceptionHandlerResponseStatusPathVariableRequestParamControllerRestControllerModelAttributeCross…...
《游戏学习》| 微信对话模拟生成器源码分析
简介微信对话生成器,是一款在线微信聊天对话制作的工具,它可以设置苹果或安卓状态栏,包括手机电量、手机时间等,还可以设置不同用户的角色,然后发送文字、语音、红包、转账等多种好玩的功能,可谓是一款娱乐…...
剑指 Offer 10- I. 斐波那契数列[c语言]
目录题目思路代码结果该文章只是用于记录考研复试刷题题目 力扣斐波那契数列 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下: F(0) 0, F(1) 1 …...
【C#基础】C# 数据类型总结
序号系列文章0【C#基础】初识编程语言C#1【C#基础】C# 程序通用结构2【C#基础】C# 基础语法解析文章目录前言数据类型一. 值类型(Value types)二. 引用类型(Reference types)三. 指针类型(Pointer types)结…...
再创荣誉 | Softing工业荣获CAIMRS 2023 数字化创新奖
在刚刚结束的中国工控-第二十一届“自动化及数字化”年度评选(CAIMRS 2023)中,Softing凭借edgeAggregator产品荣获“数字化创新奖”! 经层层筛选,Softing edgeAggregator边缘聚合服务器从中脱颖而出,摘得C…...
Multi Paxos
basic paxos 是用于确定且只能确定一个值,“只确定一个值有什么用?这可解决不了我面临的问题,例如每个用户都要多次保存数据.” 你心中可能有这样的疑问。 原simple paxos论文里有提到一连串个instance of paxos [4] 但没有提出 multi paxos的概念&…...
Android - dimen适配
一、分辨率对应DPIDPI名称范围值分辨率名称屏幕分辨率density密度(1dp显示多少px)ldpi120QVGA240*3200.75(120dpi/1600.75px)mdpi160(基线)HVGA320*4801(160dpi/1601px)hdpi240WVGA4…...
深度学习网络模型——RepVGG网络详解
深度学习网络模型——RepVGG网络详解0 前言1 RepVGG Block详解2 结构重参数化2.1 融合Conv2d和BN2.2 Conv2dBN融合实验(Pytorch)2.3 将1x1卷积转换成3x3卷积2.4 将BN转换成3x3卷积2.5 多分支融合2.6 结构重参数化实验(Pytorch)3 模型配置论文名称: RepVGG: Making V…...
仓库拣货标签应用案例
使用场景:富士康成都仓库 解决问题:仓库亮灯拣选, 提高作业效率和物料明晰展示仓库亮灯拣选使用场景:京东仓库 解决问题:播种墙分拣,合单拣货完成后按订单播种播种墙分拣使用场景:和尔泰智能料…...
介绍一款HCIA、HCIP、HCIE的刷题软件
华为认证考试分为三个等级,分别为工程师HCIA、高级工程师HCIP、专家HCIE,等级越高,考试难度越大。 本篇带大家详细了解华为数通题库刷题工具的详细操作步骤。 操作须知:本款刷题工具为一款刷题小程序,无需安装即可在线…...
线程池整理汇总
它山之石,可以攻玉。借鉴整理线程池相关文章,以及自身实践。 文章目录1. 线程池概述2. 线程池UML架构3. Executors创建线程的4种方法3.1 newSingleThreadExecutor3.2 newFixedThreadPool3.3 newCachedThreadPool3.4 newScheduledThreadPool小结4. 线程池…...
华为OD机试真题Python实现【最短木板长度】真题+解题思路+代码(20222023)
🔥系列专栏 华为OD机试(Python)真题目录汇总华为OD机试(JAVA)真题目录汇总华为OD机试(C++)真题目录汇总华为OD机试(JavaScript)真题目录汇总文章目录 🔥系列专栏题目输入输出示例一输入输出说明示例二输入输出说明...
VMware安装CentOS7
个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。个人爱好: 编程,打篮球,计算机知识个人名言:海不辞水,故能成其大;山不辞石…...
力扣24.两两交换链表中的节点
文章目录力扣24.两两交换链表中的节点题目描述方法1:非递归方法2:递归力扣24.两两交换链表中的节点 题目描述 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&…...
AtCoder Regular Contest 137 题解(A~C)
A-Coprime Pair 思路 我们知道两个质数之间并不会相隔太远,于是我们直接用暴力就可以通过这题。 先从大到小枚举答案,并且枚举所有可能的起点,当枚举到的两个值满足条件输出并结束程序即可。 代码 #include <bits/stdc.h> using n…...
【C语言】预处理指令
C语言预处理指令一、什么是预处理指令二、预处理指令特点三、文件包含四、C标准库<stdio.h>一、什么是预处理指令 C语言的源文件(.c文件)需要经过编译生成可执行程序,编译操作会将源文件转换成目标文件,对于 VC、VS&#x…...
Java基础之多线程JUC全面学习笔记
目录初识多线程多线程的实现方式常见的成员方法线程安全的问题死锁生产者和消费者线程池自定义线程池初识多线程 什么是多线程? 线程 线程是操作系统能够进行运算调度的最小单位。线程被包含在进程之中,是进程中的实际运作单位。 简单理解:应用软件中互相独立&…...
13.CSS文本样式
文本样式 h1 {color: blue; }● 回顾上一节的内容,我们让h1标题的文字变成了蓝色,注意如果html中有多个h1标签,那我们这种写法所有的h1标签都会变成蓝色,除了颜色,本节我们将学习更多的CSS属性 文字大小font-size h…...
西恩科技更新招股书:IPO前大手笔分红“套现”, 赵志安为实控人
2月14日,上海西恩科技股份有限公司(下称“西恩科技”)更新了招股书(申报稿)。据贝多财经了解,西恩科技于2022年8月12日递交上市申请材料,准备在创业板上市,此次是西恩科技第二次更新…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...
Django RBAC项目后端实战 - 03 DRF权限控制实现
项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...
react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...
