• SpringBoot中的AOP使用


    SpringBoot中的AOP使用

    1.AOP介绍

    Spring的AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,
    简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

    AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

    总结:AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。

    2. AOP 编程术语

    2.1切面(Aspect)

    切面泛指交叉业务逻辑,或是公共的,通用的业务。上例中的事务处理、日志处理就可以理解为切面。常用的切面是通知(Advice)。实际就是对主业务逻辑的一种增强。

    切面有切点和通知组成,即包括横切逻辑的定义也包括连接点的定义

    2.2连接点(JoinPoint

    连接点指可以被切面织入的具体方法。通常业务接口中的方法均为连接点。

    程序执行的某个特定位置,如某个方法调用前后等。

    2.3切入点(Pointcut)

    切入点指声明的一个或多个连接点的集合。通过切入点指定一组方法。
    被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。

    在程序应用中就是你要增强功能的类或方法(确认位置)。

    2.4目标对象(Target)

    目标对象指 将要被增强 的对象。 即包含主业 务逻辑的 类的对象。 上例中 的
    BookServiceImpl 的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然, 不被增强,也就无所谓目标不目标了。

    目标对象,通知织入的目标类。

    2.5通知(Advice)

    通知表示切面的执行时间,Advice 也叫增强。上例中的 MyInvocationHandler 就可以理解为是一种通知。换个角度来说,通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。
    切入点定义切入的位置,通知定义切入的时机。

    通知,是织入到目标类连接点上的一段代码,就是增强到什么地方?增强什么内容?

    3.切入点表达式

    3.1AspectJ表达式

    表达式共 4 个部分可简化如下:
    execution(访问权限 方法返回值 方法声明(参数) 异常类型)

    AspectJ 定义了专门的表达式用于指定切入点。

    切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表达式中明显就是方法的签名。注意,表达式中黑色文字表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:

    在这里插入图片描述

    3.2表达式举例:

    execution(public * *(..))
    指定切入点为:任意公共方法。

    execution(* set*(..))
    指定切入点为:任何一个以“set”开始的方法。

    execution(* com.xyz.service.impl.*.*(..))
    指定切入点为:定义在 service 包里的任意类的任意方法。

    execution(* com.xyz.service..*.*(..)) * com.xyz.service.power2.aa.*.*(..)
    指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“…”出现在类名中时,后面必须跟“*”,表示包、子包下的所有类。
    execution(* *..service.*.*(..)) a.b.service.*.*(..) a.b.c.d.service.*.*(..)
    指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点

    execution(* *.service.*.*(..))
    指定只有一级包下的 serivce 子包下所有类(接口)中所有方法为切入点

    4.Aspect中的通知类型

    4.1常用四种类型

    (1)前置通知@Before
    切入点方法执行之前执行的方法@Before

    (2)环绕通知@Around

    切入点前后都执行 @Around
    (3)异常通知@AfterThrowing
    切入发点方法执行异常后执行的方法@AfterThrowing:切入点里面的出现异常如10/0,才会执行的方法。
    (4)后置通知@After
    后置通知,在方法执行之后执行

    4.2相关概念

    Joinpoint(连接点)
    所谓连接点是指那些被拦截到的点,在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点,通俗的说就是被增强类中的所有方法

    PointCut(切入点)
    所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义,通俗的说就是被增强类中的被增强的方法,因为被增强类中并不是所有的方法都被代理了

    Advice(通知/增强)
    所谓通知是指拦截到 Joinpoint (被增强的方法)之后所要做的事情就是通知,通俗的说就是对被增强的方法进行增强的代码

    4.3相关注解

    @Component 将当前类注入到Spring容器内

    @Aspect :表明是一个切面类

    @Pointcut :切入点,PointCut(切入点)表达式有很多种,其中execution用于使用切面的连接点。

    5.spring boot集成AOP

    5.1环境准备

    在这里插入图片描述

    引入AOP相关的依赖

    <dependencies>
      <dependency>
             <groupId>org.springframework.bootgroupId>
             <artifactId>spring-boot-starter-aopartifactId>
      dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    创建controller测试访问

    在这里插入图片描述

    5.2实例一

    使用aop来完成全局请求日志处理
    步骤一:创建一个aspect切面类

    @Component
    @Aspect
    public class MyAop {
    
        //切入点
        //表示public 这个包下的任意方法作为切入点
        @Pointcut("execution(public * com.jierlung.controller.*.*(..))")
        public void log(){
            System.out.println("pointCut签名......");
        }
    
        //前置通知
        @Before(value = "log()")
        public void deBefore(){
            System.out.println("我是前置通知呀...");
        }
    
    
        //返回通知
        @AfterReturning(returning = "ret", pointcut = "log()")
        public void doAfterReturning(Object ret) throws Throwable {
            // 处理完请求,返回内容
            System.out.println("返回通知:方法的返回值 : " + ret);
        }
    
        //异常通知
        @AfterThrowing(throwing = "ex", pointcut = "log()")
        public void throwss(JoinPoint jp,Exception ex){
            System.out.println("异常通知:方法异常时执行.....");
            System.out.println("产生异常的方法:"+jp);
            System.out.println("异常种类:"+ex);
        }
    
        //后置通知
        @After("log()")
        public void after(JoinPoint jp){
            System.out.println("后置通知:最后且一定执行.....");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    测试访问
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    分析:
    第一步:首先通过注解形式定义切面类,把切面类注入容器,交给spring管理

    第二步:定义一个方法,加上切入点的注解,指定切哪个包下的类的所有方法,这个作为切入点,该类的方法执行时,例如我访问controller里面的方法时,这个controller就被我作为切入点,该方法执行时,会执行到切入的方法,执行相关业务代码。

    第三步:注解方式加上通知,切入点写之前定义的方法,构成一个切面(由切入点和通知组成)。

    5.3实例二

    @annotation方式

    编写一个自定义注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD,ElementType.TYPE})
    public @interface MyLogAnnotation {
    
        //定义一个变量,可以接受参数
        String desc() default " ";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    定义一个切面类

    @Component
    @Aspect
    public class MyAopAnnotation {
    
        @Pointcut(value = "@annotation(com.jierlung.annotation.MyLogAnnotation)")
        //切入点签名
        public void logAnnotation(){
            System.out.println("pointCut签名。。。");
        }
    
        //前置通知
        @Before("logAnnotation()")
        public void deBefore(JoinPoint jp) throws Throwable {
            // 接收到请求,记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 记录下请求内容
            System.out.println("URL : " + request.getRequestURL().toString());
        }
        //返回通知
        @AfterReturning(returning = "ret", pointcut = "logAnnotation()")
        public void doAfterReturning(Object ret) throws Throwable {
            // 处理完请求,返回内容
            System.out.println("返回通知:方法的返回值 : " + ret);
        }
    
        //异常通知
        @AfterThrowing(throwing = "ex", pointcut = "logAnnotation()")
        public void throwss(JoinPoint jp,Exception ex){
            System.out.println("异常通知:方法异常时执行.....");
            System.out.println("产生异常的方法:"+jp);
            System.out.println("异常种类:"+ex);
        }
    
        //后置通知
        @After("logAnnotation()")
        public void after(JoinPoint jp){
            System.out.println("后置通知:最后且一定执行.....");
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    在目标方法上加上注解
    在这里插入图片描述
    测试访问
    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    分享5款同类软件中的翘楚,属于是WIN10必备良品
    MATLAB如何将k线图设置为经典红绿配色?
    数字IC设计之时序分析基础概念汇总
    pip install paramiko出错的解决方案
    学生信息管理系统(spring+springmvc+mybatis+Layui)
    【剑指offer|图解|双指针】移除元素 + 合并两个有序数组
    Lambda表达式详解
    基于nodejs+vue美食外卖推荐网站系统源码
    LeetCode每日一题(931. Minimum Falling Path Sum)
    vector--erase()安全删除指定元素
  • 原文地址:https://blog.csdn.net/qq_52166656/article/details/128047570