• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

SpringBoot实现AOP面向切面编程

武飞扬头像
龙城桥少
帮助1

目录

一、为什么需要面向切面编程?

二、Spring AOP术语

三、Spring Boot AOP实现

3.1 引入依赖

3.2 编写用于拦截的bean

3.3 定义切面

3.3.1 定义切点

3.3.2 定义通知

3.3.3 前置、后置、返回、异常通知的切入:

3.3.4 环绕通知


一、为什么需要面向切面编程?

        面向对象编程(OOP)的好处是显而易见的,缺点也同样明显。当需要为多个不具有继承关系的对象添加一个公共的方法的时候,例如日志记录、性能监控等,如果采用面向对象编程的方法,需要在每个对象里面都添加相同的方法,这样就产生了较大的重复工作量和大量的重复代码,不利于维护。面向切面编程(AOP)是面向对象编程的补充,简单来说就是统一处理某一“切面”的问题的编程思想。如果使用AOP的方式进行日志的记录和处理,所有的日志代码都集中于一处,不需要再每个方法里面都去添加,极大减少了重复代码。

二、Spring AOP术语

1、通知(Advice):就是我们上面提到的除了业务代码本身之外,一些“可重用的一些代码”,先定义好,在需要的地方进行重用;

2、连接点(JoinPoint):允许你使用“通知”的地方,就是允许你重复使用代码的地方,方法执行的前后或者方法抛出异常时,Spring只支持方法级别的连接点;

3、切入点(Pointcut): 假如有若干方法,但是我们并不是想在所有的方法中“重用这段可复用的代码”,我们只想在某些特定的方法上使用通知,那么我们就可以使用切入点来进行这些连接点的“筛选了”;

4、切面(Aspect):切面简单来讲就是切入点(JoinPoint)和通知(Advice)的结合体。通知(Advice)决定了要干什么(通知的方法体)?在什么时候干?(定义通知的注解类型)。而切入点决定了要在哪儿干(即执行通知定义的方法体)。

5、引入(Introduction):允许我们向目标对象添加新的方法属性(即通过执行通知来控制对目标方法的访问);

6、目标对象(Target):引入中所提到的目标对象,也就是要被通知的对象,也就是执行真正的业务逻辑,可以在毫不知情的情况下,织入我们的切面;

7、代理(Proxy):Spring中的AOP都是通过动态代理来实现的;

8、织入(Weaving):把切面应用到目标对象,创建代理对象的过程;

三、Spring Boot AOP实现

3.1 引入依赖

Spring Boot使用AOP需要添加spring-boot-starter-aop依赖,如下:

  1.  
    <dependency>
  2.  
    <groupId>org.springframework.boot</groupId>
  3.  
    <artifactId>spring-boot-starter-aop</artifactId>
  4.  
    </dependency>

3.2 编写用于拦截的bean

直接定义一个controller,代码如下:

  1.  
    @RestController
  2.  
    public class UserController {
  3.  
     
  4.  
    @RequestMapping("/")
  5.  
    public String hello(){
  6.  
    System.out.println("我就是被切入的目标对象的方法!");
  7.  
    return "";
  8.  
    }
  9.  
    }

3.3 定义切面

Spring采用@Aspect注解对目标类进行标注,该注解表明该类不仅仅是一个目标类,还是一个切面。切面是切点和通知的结合,那么定义一个切面就需要编写切点和通知。在代码中,不仅需要添加@Aspect注解还需要添加@Component组件注解,表示被扫描并提交给Spring管理。

3.3.1 定义切点

切点是通过@Pointcut注解和切点表达式定义的。

@Pointcut注解可以在一个切面内定义可重用的切点。

由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的部件,并且实际中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。如图是execution表达式的语法:

学新通

execution表示在方法执行的时候触发。以“*”开头,表明方法返回值类型为任意类型。然后是全限定的类名和方法名,“*” 可以表示任意类和任意方法。对于方法参数列表,可以使用“..”表示参数为任意类型。如果需要多个表达式,可以使用“&&”、“||”和“!”完成与、或、非的操作。

3.3.2 定义通知

通知有五种类型,分别是:

前置通知(@Before):在目标方法调用之前调用通知

后置通知(@After):在目标方法完成之后调用通知

返回通知(@AfterReturning):在目标方法成功执行之后调用通知

异常通知(@AfterThrowing):在目标方法抛出异常之后调用通知

环绕通知(@Around):在被通知的方法调用之前和调用之后执行自定义的方法

环绕通知中可以实现其他所有通知,所以我们用代码来分别显示:

3.3.3 前置、后置、返回、异常通知的切入:

  1.  
    @Component
  2.  
    @Aspect
  3.  
    public class AnnotationAOP {
  4.  
     
  5.  
    @Pointcut("execution(* com.songqiao.controller.UserController.hello())")
  6.  
    public void PointCut(){}
  7.  
     
  8.  
    //通过JoinPoint接口可以获取到方法名
  9.  
    @Before("PointCut()")
  10.  
    public void beforeAOP(JoinPoint joinPoint){
  11.  
    String methodName = joinPoint.getSignature().getName();
  12.  
    System.out.println("前置通知已执行!被切入的方法名是" methodName);
  13.  
    }
  14.  
     
  15.  
    @After("PointCut()")
  16.  
    public void afterAOP(){
  17.  
    System.out.println("后置通知已执行!");
  18.  
     
  19.  
    }
  20.  
     
  21.  
    @AfterReturning("PointCut()")
  22.  
    public void afterReturningAOP(){
  23.  
    System.out.println("返回通知已执行!");
  24.  
    }
  25.  
    //通过throwing属性可以获取到异常信息
  26.  
    @AfterThrowing(value = "PointCut()",throwing = "ex")
  27.  
    public void afterThrowingAOP(Throwable ex){
  28.  
    System.out.println("异常通知!异常信息为:" ex);
  29.  
    }
  30.  
    }
学新通

当我们的切入的方法产生异常时,会执行切入的异常通知并通过 throwing属性获取异常信息并输出,由于发生异常,方法没有执行return 语句,所以返回通知不会执行。请看效果:

 测试:

学新通

 当我们把异常报错修改后即可执行返回通知。所以说返回通知与异常通知只能执行一个!

学新通

3.3.4 环绕通知

环绕通知就是AOP的动态代理模式,可以封装以上所有的通知。

  1.  
    @Component
  2.  
    @Aspect
  3.  
    public class AnnotationAOP {
  4.  
    @Pointcut("execution(* com.songqiao.controller.UserController.hello())")
  5.  
    public void PointCut(){}
  6.  
     
  7.  
    @Around("PointCut()")
  8.  
    public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint){
  9.  
    Object result=null;
  10.  
    try {
  11.  
    //前置通知位置
  12.  
    System.out.println("环绕的前置通知");
  13.  
    //相当于是目标对象方法的执行
  14.  
    result = joinPoint.proceed();
  15.  
    //返回通知位置
  16.  
    System.out.println("环绕的返回通知");
  17.  
    } catch (Throwable throwable) {
  18.  
    //异常通知位置
  19.  
    throwable.printStackTrace();
  20.  
    System.out.println("环绕的异常通知");
  21.  
    }finally {
  22.  
    //后置通知位置
  23.  
    System.out.println("环绕的后置通知");
  24.  
    }
  25.  
    return result;
  26.  
    }
  27.  
    }
学新通

测试:

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbhfie
系列文章
更多 icon
同类精品
更多 icon
继续加载