【Spring Boot】Spring AOP中的环绕关照

王柳  金牌会员 | 2024-12-30 15:39:37 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 821|帖子 821|积分 2463

目次





    • 一、什么是AOP?
    • 二、AOP 的环绕关照


      • 2.1 切点以及切点表达式
      • 2.2 毗连点
      • 2.3 关照(Advice)
      • 2.4 切面(Aspect)
      • 2.5 不同关照范例的区别


        • 2.5.1 正常环境下
        • 2.5.2非常环境下

      • 2.6 统一管理切点@PointCut


一、什么是AOP

Aspect Oriented Programming(面向切面编程)
AOP是Spring框架的第核(第核是IoC)
AOP是一种思想,是对某一类事情的集中处置处罚。
此中在下面的学习中我们会学习到拦截器、统一非常处置处罚,统一结果处置处罚等,这些都是运用了AOP的统一思想来实现的。
拦截器实现AOP思想作用的维度是前端对后端进行的一次请求和一次响应,主要是检索前端传来的URL,如果检索后返回True,则可以进入Controller开始执行代码,如果返回的为False,则表示失败,直接被拦截在外面,无法执行代码。
统一结果处置处罚则是使用注解@ControllerAdvice(关照类注解),实现ResponseBodyAdvice接口,对响应的结果进行统一处置处罚,对齐进行统一的包装后响应,此中如果数据范例为String范例的话要进行特殊处置处罚,使用ObjectMapper的方法将String格式转为Json格式再次响应。
统一非常处置处罚也是使用注解@ControllerAdvice(关照类注解),以及在方法上使用@ExceptionHandler注解,在全部的步调中如果遇到运行时非常则会自动捕捉,进行抛出,注:编译时非常是写代码过程中出现的,不手动解决就无法运行步调。
接下来我们要学习的是运用了AOP思想,进行AOP的环绕处置处罚
二、AOP 的环绕关照

2.1 切点以及切点表达式

切点=关照范例+切点表达式
切点表示了为该方法提供一组规则,来对步调进行功能增强
关照范例有以下5种:
   @Around:环绕关照,此注解标注的关照方法在目标方法前,后都被执行
@Before:前置关照,此注解标注的关照方法在目标方法前被执行
@After:后置关照,此注解标注的关照方法在目标方法后被执行,论是否有非常都会执行
@AfterReturning:返回后关照,此注解标注的关照方法在目标方法后被执行,有非常不会执行
@AfterThrowing:非常后关照,此注解标注的关照方法发非常后执行

  如下图所示:

在该方法上的@Around,表示的是环绕处置处罚,是一种关照范例
其后面的execution(* com.example.demo.controller..(…)) 表示的是该关照范例作用的范围,是切点表达式
2.2 毗连点

满意切点表达式规则的方法就是毗连点

在该图中,public recordTime方法就是毗连点
2.3 关照(Advice)

关照就是具体要做的内容,简单来说就是方法内执行的代码内容
如图所示:

该图中标红的位置就是关照内容,在AOP面向切面编程当中,我们把这部分重复的代码逻辑抽取出来单独界说,这部分代码就是关照的内容
2.4 切面(Aspect)

起首使用注解@Aspect来表示该类是一个切面类
然后使用不同的关照范例进行处置处罚,如图表示的是环绕关照范例
在处置处罚过程中ProceedingJoinPoint.proceed()让原始方法执行

切面(Aspect)=切点(Pointcut)+关照(Advice)
以下代码表示一个完整的切面类:
  1. import lombok.extern.slf4j.Slf4j;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import org.aspectj.lang.annotation.Around;
  4. import org.aspectj.lang.annotation.Aspect;
  5. import org.springframework.stereotype.Component;
  6. @Slf4j
  7. @Aspect
  8. @Component
  9. public class TimeAspect {
  10.         /**
  11.         * 记录方法耗时
  12.         */
  13.         @Around("execution(* com.example.demo.controller.*.*(..))")
  14.         public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
  15.                 //记录方法执行开始时间
  16.                 long begin = System.currentTimeMillis();
  17.                
  18.                 //执行原始方法
  19.                 Object result = pjp.proceed();
  20.                
  21.                 //记录方法执行结束时间
  22.                 long end = System.currentTimeMillis();
  23.                
  24.                 //记录方法执行耗时
  25.                 log.info(pjp.getSignature() + "执行耗时: {}ms", end - begin);
  26.                
  27.                 return result;
  28.         }
  29. }
复制代码
2.5 不同关照范例的区别

2.5.1 正常环境下

环绕关照 @Around 标识的关照方法包罗两部分,个"前置逻辑",个"后置逻辑".其
中"前置逻辑"会先于 @Before 标识的关照方法执行,"后置逻辑"会晚于 @After 标识的关照方法执行

2.5.2非常环境下

步调发非常的环境下:
@AfterReturning 标识的关照方法不会执行, @AfterThrowing 标识的关照方法执行了
@Around 环绕关照中原始方法调时有非常,关照中的环绕后的代码逻辑也不会在执行了(因为
原始方法调出非常了)

注意事项:
@Around 环绕关照必要调 ProceedingJoinPoint.proceed() 来让原始方法执行,其他
关照不必要考虑目标方法执行.
@Around 环绕关照方法的返回值,必须指定为Object,来接收原始方法的返回值,否则原始方法执
行完毕,是获取不到返回值的.
个切面类可以有多个切点
2.6 统一管理切点@PointCut

统一管理切点就是对于复杂的切点表达式进行提取,然后用@PointCut注解方法进行单独声明,再本类下面的步调中如果用到该切点表达式,则直接使用注解后的方法即可,如果在其他类中使用该声明事后的切点表达式则必要使用全路径限定名+该方法即可
本类使用注解后的切点表达式代码如下:
  1. @Slf4j
  2. @Aspect
  3. @Component
  4. public class AspectDemo {
  5.                 //定义切点(公共的切点表达式)
  6.                 @Pointcut("execution(* com.example.demo.controller.*.*(..))")
  7.                 private void pt(){}
  8.                
  9.                 //前置通知
  10.                 @Before("pt()")
  11.                 public void doBefore() {
  12.                 //...代码省略
  13.                 }
  14.                
  15.                 //后置通知
  16.                 @After("pt()")
  17.                 public void doAfter() {
  18.                 //...代码省略
  19.                 }
  20.                
  21.                 //返回后通知
  22.                 @AfterReturning("pt()")
  23.                 public void doAfterReturning() {
  24.                 //...代码省略
  25.                 }
  26.                
  27.                 //抛出异常后通知
  28.                 @AfterThrowing("pt()")
  29.                 public void doAfterThrowing() {
  30.                 //...代码省略
  31.                 }
  32.                
  33.                 //添加环绕通知
  34.                 @Around("pt()")
  35.                 public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
  36.                 //...代码省略
  37.         }
  38. }
复制代码
在其他类中调用该切点表达式代码如下:
  1. @Slf4j
  2. @Aspect
  3. @Component
  4.         public class AspectDemo2 {
  5.                 //前置通知
  6.                 @Before("com.example.demo.aspect.AspectDemo.pt()")
  7.                 public void doBefore() {
  8.                 log.info("执行 AspectDemo2 -> Before 方法");
  9.         }
  10.        
  11. }```
  12. 当切点定义使?private修饰时,仅能在当前切面类中使?,当其他切面类也要使?当前切点定义时,就需要把private改为public.引?方式为:全限定类名.方法名()
  13. ### 2.7     切面优先级@Order
  14. 在切面类中会有多个切点同时匹配成功,那么该如何进行执行顺序呢?
  15. 应该使用注解@Order(数字)来表示优先级顺序
  16. @Order注解标识的切面类,执行顺序如下:
  17. ? @Before 通知:数字越?先执行
  18. ? @After 通知:数字越?先执行
  19. @Order 控制切面的优先级,先执行优先级较?的切面,再执行优先级较低的切面,最终执行目标方法.
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表