java springboot AOP切面编程

AOP

我们现在从Controller的角度来看这个代理对象,本来我们的Controller在使用Service时,Service的实例对象是容器提供给我们的,现在如果我们需要代理对象完成新增的较长业务,代理的对象创建也应该交给容器来实现,这个过程就是aop。aop:面相切面编程(百度,务必要总结)。面向对象编程oop。

在通知spring容器创建代理对象时,我们需要告知容器以下几点:

1、哪些类的哪些方法需要使用代理对象。

2、指出交叉业务是在目标方法的什么位置实现:前面,后面,前后、出现异常时

3、交叉业务的逻辑

添加依赖

直接引用springboot的依赖,同时引入aop的相关依赖

    <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.5.3</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

配置启动类

@SpringBootApplication
@EnableAspectJAutoProxy  //启动切面(即启动自动代理)
public class AopApp {public static void main(String[] args) {SpringApplication.run(AopApp.class, args);}

配置切面Aspect

切面 = 被增强的目标对象 + 切入点(需要增加交叉业务的目标方法)+ 交叉业务逻辑

//切面类
@Component  //切面类也需要创建实例
@Aspect  //表示当前类是一个切面类
public class MyAspect {//定义切入点Pointcut(指明哪些类的哪些方法需要增强(交叉业务))
//value属性接收一个execution表达式,我们使用execution表达式来确认目标方法
//下面示例中的表达式表示要为com.wngz.aop.service.UserService接口中所有的方法,无论什么参数都要进行增强@Pointcut(value = "execution(* com.wngz.aop.service.*.*(..))")public void initPointcut() {
//方法中啥也不用写,关键是这个方法上的切入点相关注解}//在所有目标方法运行前,显示提示文字. JoinPoint连接点,就是执行核心业务的方法@Before(value = "initPointcut()")public void myBefore(JoinPoint joinPoint) {System.out.printf("------- 马上要开始执行方法(%s)了 -------\n", joinPoint.getSignature().getName());}
}

修改UserServiceImpl

@Service
public class UserServiceImpl implements UserService {

加上这个注解后,我们还是通过spring容器正常获取UserService,但是得到的对象就是增强后的对象了

测试类

@SpringBootTest(classes = {AopApp.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class AppTest {@AutowiredUserService userService;@Testpublic void myTest() {userService.login("alice", "678");System.out.println(userService.getMessage(11));}
}

Aop控制方法连续点击

@Aspect
@Component
public class IdemAspect {private final RedisTemplate redisTemplate;public IdemAspect(RedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}@Before(value = "@annotation(idemAnnotation)")public void before(JoinPoint joinPoint, IdemAnnotation idemAnnotation) {String key = joinPoint.getSignature().getName();for (Object arg : joinPoint.getArgs()) {key += "_" + arg.hashCode();}if (redisTemplate.hasKey(key)) {throw new BusinessException(BusinessErrorEnum.REPEAT_SUBMIT);}redisTemplate.opsForValue().set(key, "", idemAnnotation.timeout(), idemAnnotation.timeunit());}
}

增强的时机

//切面类
@Component  //切面类也需要创建实例
@Aspect  //表示当前类是一个切面类
public class MyAspect {@Before(value = "@annotation(idemAnnotation)")//有注解idemAnnotation的方法为切入点public void before(JoinPoint joinPoint, IdemAnnotation idemAnnotation) {//相关方法}//定义切入点Pointcut(指明哪些类的哪些方法需要增强(交叉业务))//value属性接收一个execution表达式,我们使用execution表达式来确认目标方法//下面示例中的表达式表示要为com.wngz.aop.service.UserService接口中所有的方法,无论什么参数都要进行增强@Pointcut(value = "execution(* com.aop.service.UserService.*(..))")public void initPointcut() {//方法中啥也不用写,关键是这个方法上的切入点相关注解}//在所有目标方法运行前,显示提示文字. JoinPoint连接点,就是执行核心业务的方法@Before(value = "initPointcut()")public void myBefore(JoinPoint joinPoint) {System.out.printf("------- 马上要开始执行方法(%s)了 -------\n", joinPoint.getSignature().getName());}//在目标方法成功执行后做增强@AfterReturning(value = "initPointcut()")public void mySuccess(JoinPoint joinPoint) {System.out.printf("------- 方法(%s)正常执行结束了 -------\n", joinPoint.getSignature().getName());}//使用@After注解,无论是否发生异常都会触发@After(value = "initPointcut()")public void myFinally(JoinPoint joinPoint) {System.out.printf("+++++++ 方法(%s)执行结束了 +++++++\n\n", joinPoint.getSignature().getName());}//拦截异常(必须明确指定异常变量的名称)@AfterThrowing(value = "initPointcut()", throwing = "ex10")public void handleException(JoinPoint joinPoint, Exception ex10) {System.out.printf("+++++++ 执行方法(%s)出现异常,原因是:%s +++++++\n",joinPoint.getSignature().getName(),ex10.getMessage());}//环绕增强, 注意环绕增加方法中的参数类型不是简单的切入点,而是可以执行的切入点类型@SneakyThrows@Around(value = "initPointcut()")public Object around(ProceedingJoinPoint pjp) {long startTime = System.currentTimeMillis();Object result = pjp.proceed();long endTime = System.currentTimeMillis();System.out.printf("====== 方法(%s)用时(%s)毫秒 ======\n",pjp.getSignature().getName(),endTime - startTime);return result;}
}
@Service
public class UserServiceImpl implements UserService {@Overridepublic void login(String username, String pwd) {System.out.printf("用户%s登录成功!\n", username);}@Overridepublic String getMessage(Integer id) {
//int i = 1 / 0; //如果测试环绕增强,就不要制造异常,否则看不到返回结果return "用户的id为:" + id;}
}

制造异常,验证("@AfterThrowing")的使用效果

execution表达式

execution表达式目的是选中我们要加入AOP编程的方法,即连接点。匹配特定包中的特定类中特定返回值类型的特定参数的特定方法。

语法:execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)

除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。

通过方法签名定义切点

execution(public * *(..))
匹配所有目标类的public方法,但不匹配protected void showGoods()方法。第一个*代表返回类型,第二个*代表方法名,而..代表任意形参的方法;
execution(* *To(..))
匹配目标类所有以To为后缀的方法。第一个*代表返回类型,而*To代表任意以To为后缀的方法;

通过类定义切点

execution(* com.baobaotao.UserService.*(..))
匹配Waiter接口的所有方法,第一个*代表返回任意类型,com.baobaotao.Waiter.*代表Waiter接口中的所有方法
execution(* com.baobaotao.Waiter+.*(..))
匹配Waiter接口及其所有实现类的方法,它不但匹配实现类中接口定义的方法,同时还匹配没有在Waiter 接口中定义的其他方法。

通过包定义切点

在类名模式串中,"."表示包下的所有类,而".."表示包、子孙包下的所有类。
execution(* com.baobaotao.*(..))
匹配com.baobaotao包下所有类的所有方法;
execution(* com.baobaotao..*(..))
匹配com.baobaotao包、子孙包下所有类的所有方法,如com.baobaotao.dao,com.baobaotao.servier以及 com.baobaotao.dao.user包下的所有类的所有方法都匹配。".."出现在类名中时,后面必须跟"*",表示包、子孙包下的所有类;
execution(* com..*.*Dao.find*(..))
匹配包名前缀为com的任何包下类名后缀为Dao的类,方法名必须以find为前缀。如com.baobaotao.UserDao#findByUserId()、com.baobaotao.dao.ForumDao#findById()的方法都匹配切点。
<!--配置pointcut切入点,匹配名称以ServiceImpl结尾类中所有方法-->
@Pointcut(value = "execution(* com.woniu.spring_ioc.service.impl.*ServiceImpl.*(..))")<!-- 配置pointcut切入点,匹配com.woniu.spring_ioc.service.impl包下所有类中所有方法。Impl后面的两个点之间其实是匹配所有后代类名。最后那个*匹配的是所有方法名 -->
@Pointcut(value = "execution(* com.woniu.spring_ioc.service.impl..*(..))")<!-- OrderService接口中方法名以st结尾的方法 -->
@Pointcut(value = "execution(* com.woniu.spring_ioc.service.OrderService.*st(..))")<!-- OrderServiceImpl类中方法名以in结尾的方法 -->
@Pointcut(value = "execution(* com.woniu.spring_ioc.service.impl.OrderServiceImpl.*in(..))")<!-- service包中所有类的方法名以logo开始的方法 -->
@Pointcut(value = "execution(* com.woniu.spring_ioc.service.*.logo*(..))")<!-- 类名以Impl结束的类中所有包含两个字符串参数的方法 -->
@Pointcut(value = "execution(* com.woniu.spring_ioc..*Impl.*(String, String))")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/5042.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

真题--数组循环题目

1.逆序数表达数组2.用数组表示费波纳希数列3.用数组排序4.二维数组转置5.找到二维数组其中的最大数值6.输出字符数组7.字符数组输出菱形图案8.输入一行字符&#xff0c;统计有多少单词9.有三个字符串&#xff0c;找到最大字符串 1.逆序数表达数组 #include<stdio.h> int…

精美的Python Rich

今天给大家推荐一个非常精美的终端工具 - Python Rich Rich 是一个专为 Python 开发者打造的终端美化库&#xff0c;能让你的控制台输出内容更具视觉效果&#xff01;通过简单易用的 Rich API&#xff0c;可以快速为终端文本添加颜色和样式&#xff0c;让原本单调的输出变得丰…

【react框架之dvajs】dva数据流你可能还不知道的subscriptions隐藏的秘密

Subscriptions 是一种从 源 获取数据的方法&#xff0c;它来自于 elm。 语义是订阅&#xff0c;用于订阅一个数据源&#xff0c;然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket连接、keyboard 输入、geolocation 变化、history 路由变化等等…

基于单片机的燃气报警阀门系统

本设计基于单片机的燃气报警阀门系统&#xff0c;燃气报警阀门系统采用STM32主控制器为核心芯片&#xff0c;外围电路由燃气传感器、OLED液晶显示模块、按键模块、蜂鸣器报警模块、电磁阀以及SIM800模块等模块组成。燃气传感器模块负责采集燃气浓度数据&#xff0c;采集完成由S…

python怎么去掉换行符

换行符与其他字符并没有区别&#xff0c;由于换行符总是最后一个字符&#xff0c;所以直接选择除去最后一个字符的所有字符即可。 x abc\n x[:-1] 也可以使用字符串的strip()方法 但是strip()方法除了会去掉换行符&#xff0c;还会去掉空格等其他字符。 x.strip()

Webserver(4.4)多进程/多线程实现并发服务器

目录 多进程实现并发服务器多线程实现并发服务器TCP状态转换 多进程实现并发服务器 要实现TCP服务器处理并发的任务&#xff0c;使用多线程或者多进程来解决 一个父进程&#xff0c;多个子进程 父进程负责等待并接受客户端的连接 子进程&#xff1a;完成通信&#xff0c;接收一…

Pinterest会成为亚马逊的新流量入口吗?

Pinterest 作为一个以图片分享为主的社交媒体平台&#xff0c;全球月活跃用户约为 4.368亿。同时&#xff0c;Pinterest 的用户群体以女性为主&#xff0c;占比高达 70% 以上&#xff0c;且多数是 18 岁到 44 岁之间的中高收入人群&#xff0c;具有较强的购买力和消费能力。对于…

SpeechT5 模型

微软开源的 SpeechT5 语音模型&#xff0c;主要包括以下功能 语音转文字&#xff1a;用于自动语音识别&#xff08;ASR&#xff09;。文字转语音&#xff1a;用于合成音频&#xff08;TTS&#xff09;。语音转语音&#xff1a;用于不同声音之间的转换或进行语音增强。 T5 网络…

.NET 8 中 Entity Framework Core 的使用

本文代码&#xff1a;https://download.csdn.net/download/hefeng_aspnet/89935738 概述 Entity Framework Core (EF Core) 已成为 .NET 开发中数据访问的基石工具&#xff0c;为开发人员提供了强大而多功能的解决方案。随着 .NET 8 和 C# 10 中引入的改进&#xff0c;开发人…

我要精通前端-块级元素和行内元素再度深入学习笔记

真的发现前端天天增删改查&#xff0c;真的是问一些比较细节的知识&#xff0c;我真的懂么 1、块级元素间的margin会重叠&#xff0c; <div class"head"></div> <div class"content"></div>.head {margin: 5px;border: 10px sol…

sparkSQL的UDF,最常用的regeister方式自定义函数和udf注册方式定义UDF函数 (详细讲解)

- UDF&#xff1a;一对一的函数【User Defined Functions】 - substr、split、concat、instr、length、from_unixtime - UDAF&#xff1a;多对一的函数【User Defined Aggregation Functions】 聚合函数 - count、sum、max、min、avg、collect_set/list - UDTF&#xff1a;…

[SAP ABAP] 面向对象程序设计-类和对象

面向对象开发的特点&#xff1a;封装、继承和多态 什么是类和对象&#xff1f; 类(CLASS)是创建对象的模板&#xff0c;对象(OBJECT)是类的实例 一个类可以创建多个对象 类 > 类型 对象 > 个体 在ABAP语言中&#xff0c;定义一个类&#xff0c;需要包含定义(defin…

需求不明确时如何设计测试用例?

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、与产品澄清问题 需求不明确时&#xff0c;首先&#xff0c;应弄明白&#xff0c;需求有哪些模块及功能算法不明确&#xff1f; 需求有问题找相关负责人沟通…

C++:多态中的虚/纯虚函数,抽象类以及虚函数表

我们在平时&#xff0c;旅游或者是坐高铁或火车的时候。对学生票&#xff0c;军人票&#xff0c;普通票这些概念多少都有些许耳闻。而我们上篇文章也介绍过了继承与多继承。如果这些票我们都分别的去写一个类&#xff0c;当然很冗余&#xff0c;这里我们便可以去使用继承&#…

Sun Solaris开机自启配置

Sun Solaris 开机自启配置 1. 运行级别定义&#xff08;rc0.d — rcS.d&#xff09; Linux/Solaris系统启动相关目录、脚本说明&#xff1a; init: 系统启动超级进程inittab: 进程启动配置init.d: 启动脚本存放目录rc0---rc6: 运行级别目录rcS: 单用户模式启动脚本 Linux/S…

机器学习—例子:图像识别

在上篇文章中&#xff0c;在一个需求预测示例中看到了神经网络是如何工作的&#xff0c;那么如何将类似类型的想法应用于计算机视觉应用程序。 如果你正在开发人脸识别应用程序&#xff0c;让我们深入研究一下。假设一个神经网络将这样的图片作为输入&#xff0c;并输出图片中…

微服务系列五:避免雪崩问题的限流、隔离、熔断措施

目录 实验环境说明 前言 一、一片小雪花引起的雪崩&#xff01; 1.1 雪崩问题&#xff08;级联失败问题&#xff09;示意图 1.2 雪崩问题的产生原因与解决策略 二、雪崩问题的具体解决策略 2.1 请求限流 2.2 线程隔离 2.3 服务熔断 2.4 总结——具体解决策略 三、微…

C语言之写一个修改数组内容的函数

问题代码: 函数ltrim是为了消除buf字符数组中左边空格&#xff0c; memmove函数介绍 如果对c语言指针运用非常熟练的人,结合函数功能就会发现这个代码非常的傻逼&#xff0c;你会发现为什么需要返回&#xff0c;buf不用接收返回值&#xff0c;执行这个函数后buf中的内容就已经…

第二十七章 Vue异步更新之$nextTick

目录 一、概述 二、完整代码 2.1. main.js 2.2. App.vue 一、概述 需求&#xff1a;编辑标题, 弹出显示编辑框自动聚焦 1. 点击编辑&#xff0c;显示编辑框 2. 让编辑框&#xff0c;立刻获取焦点 我们常规的思路可能会编写如下代码来实现&#xff1a; 问题&#xff1a…

【含文档】基于ssm+jsp的IT论坛系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: apache tomcat 主要技术: Java,Spring,SpringMvc,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定义了三个…