热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringbootAop使用

1、什么是AOPAOP(AspectOrientedProgramming),面向切面思想,是Spring的三大核心思想之

1、什么是AOP

AOP(Aspect Oriented Programming),面向切面思想,是Spring的三大核心思想之一(两外两个:IOC-控制反转、DI-依赖注入)

个人理解:Aop是在业务流程中增加新的通用流程时,如添加日志,统计方法运行时间等时,做一个拦截,在方法执行前后,都可以做额外的动作,可以做一些无关业务流程的工作如添加日志,也可以对业务流程进行干涉,如对参数进行修改,返回值进行修改等。类似python的装饰器的作用。


2、Aop工作流程

1、定义一个切点Pointcut,切点主要是用来定义在哪里切入,比如对所有的get请求进行请求前添加日志,那么就需要针对所有@GetMapping注解的方法进行拦截

2.定义一个针对切点的处理方法Advice,这个主要来定义什么时候进行处理,方法执行前,方法执行后(专业术语:前置和后置处理)


3.代码实现


1、引入依赖

org.springframework.bootspring-boot-starter-aop


2、创建AOP类

 使用@Aspect进行注解,来标记是一个切面类


3、定义切点方法

使用@Pointcut进行方法注解,注解参数表明是对什么方法或类等进行拦截

该注解有两种类型的参数:一个是使用 execution(),另一个是使用 annotation()

execution表达式可以详细参考

execution表达式详解

execution (* com.sample.service.impl..*.*(..))

annotation() 方式是针对某个注解来定义切点

@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")

4、定义处理方法

有5个注解

1.@Before  标注的方法在切面切入目标方法之前执行

2.@After   标注的方法在切面切入目标方法之后执行

3.@Arround  可以自由选择增强动作与目标方法的执行顺序,也就是说可以在增强动作前后,甚至过程中执行目标方法,因为被@Arround标注的方法第一个形参必须是ProceedingJoinPoint类型,调用ProceedingJoinPoint参数的procedd()方法才会执行目标方法,这个方法的调用时机自己可以进行控制,没有调用ProceedingJoinPointproceed方法,则目标方法不会执行。

@Around可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值

调用ProceedingJoinPointproceed方法时,还可以传入一个Object[ ]对象,该数组中的值将被传入目标方法作为实参,所以可以改变执行目标方法的参数。传入的Object[ ]数组长度与目标方法所需要的参数必须相等。

4、@AfterReturning 注解和 @After 有些类似,区别在于 @AfterReturning 注解可以用来捕获切入方法执行完之后的返回值,对返回值进行业务逻辑上的增强处理

5、当被切方法执行过程中抛出异常时,会进入 @AfterThrowing 注解的方法中执行,在该方法中可以做一些异常的处理逻辑

6、多个


5、示例

package com.ljx.splearn.AopDemo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;/*** @author lijianxi* @date 2022年11月09日 10:58 上午*/
@Order(0)
//标注该类是切面类
@Aspect
//交给spring容器
@Component
public class LogAdvice {//@Pointcut 注解定义什么时机进行拦截,要拦截的是什么东西,一个是使用 execution(),另一个是使用 annotation()。//annotation() 方式是针对某个注解来定义切点,execution指明哪些类或包或方法被执行的表达式//表明什么时机进行切入,本例中是被getmapping注解到的方法被调用时(参数是一个注解,表示被该注解标注的方法调用时进行切入)@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")private void pointCut(){}public long t1 ;public long t2;//指定的方法在切面切入目标方法之前执行,注入后做什么动作,参数是切点方法@Before("pointCut()")public void logAdvice(JoinPoint joinPoint){// 获取签名Signature signature = joinPoint.getSignature();// 获取切入的包名String declaringTypeName = signature.getDeclaringTypeName();// 获取即将执行的方法名String funcName = signature.getName();System.out.println("执行前开始记录");t1 = System.currentTimeMillis();}//指定的方法在切面切入目标方法之后执行@After("pointCut()")public void logAdvice1(JoinPoint joinPoint) throws Throwable {Object[] args = joinPoint.getArgs();String name =(String) args[0];System.out.println("结束记录1"+name);t2=System.currentTimeMillis();System.out.println("执行时间"+(t2-t1));}//自由选择增强动作与目标方法的执行顺序@Around("pointCut()")//方法参数必须是ProceedingJoinPoint,而不能是JoinPointpublic Object logAdvice2(ProceedingJoinPoint joinPoint) throws Throwable {//获取请求参数Object[] args = joinPoint.getArgs();String name =(String) args[0];System.out.println("结束记录2"+name);t2=System.currentTimeMillis();System.out.println("执行时间1"+(t2-t1));//修改参数args[0]="王五";joinPoint.proceed(args);//修改返回值return "hello ,zhangsan";}/*** 在上面定义的切面方法返回后执行该方法,可以捕获返回对象或者对返回对象进行增强* @param joinPoint joinPoint* @param result result* 属性 returning 的值必须要和参数保持一致*/@AfterReturning(pointcut = "pointCut()", returning = "result")public void doAfterReturning(JoinPoint joinPoint, Object result) {Signature signature = joinPoint.getSignature();String classMethod = signature.getName();System.out.println((String.format("方法%s执行完毕",classMethod)));System.out.println(result);// 实际项目中可以根据业务做具体的返回值增强System.out.println("对返回参数进行业务上的增强:{}"+result + "增强版");}/*** 在上面定义的切面方法执行抛异常时,执行该方法* @param joinPoint jointPoint* @param ex ex*/@AfterThrowing(pointcut = "pointCut()", throwing = "ex")public void afterThrowing(JoinPoint joinPoint, Throwable ex) {Signature signature = joinPoint.getSignature();String method = signature.getName();// 处理异常的逻辑System.out.println((String)(String.format("执行方法{}出错,异常为:{}", method, ex)));}}

package com.ljx.splearn.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.Mapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.sql.Time;/*** @author lijianxi* @date 2022年11月09日 10:55 上午*/
@RestController
@RequestMapping("/demo")
public class DemoController {@GetMapping("/hello")String sayHello(String name) throws InterruptedException {System.out.println("传递过来参数是"+name);Thread.sleep(2000);return "hello"+name;}
}

发起请求,参数是lisi,中间对参数修改传递到controller层时是王五,最终结果被@Around修改

最终返回是zhangsan

 日志打印

 


推荐阅读
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • 解决java.lang.IllegalStateException: ApplicationEventMulticaster not initialized错误的方法和原因
    本文介绍了解决java.lang.IllegalStateException: ApplicationEventMulticaster not initialized错误的方法和原因。其中包括修改包名、解决service name重复、处理jar包冲突和添加maven依赖等解决方案。同时推荐了一个人工智能学习网站,该网站内容通俗易懂,风趣幽默,值得一看。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
author-avatar
墨镜猛女班长
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有