Spring AOP的介绍与实现

比眉伴天荒 2024-03-17 22:32 179阅读 0赞

文章目录

  • Spring AOP
      1. Spring AOP概念
      1. Spring AOP的作用
    • 3.AOP的组成
      1. Spring AOP的实现
      • 4.1 添加Spring AOP依赖
      • 4.2 定义切面(创建切面类)
      • 4.3 定义切点(配置拦截规则)
        • 4.3.1 切点表达式语法
      • 4.4 定义通知的实现
      1. Spring AOP实现原理

Spring AOP

1. Spring AOP概念

AOP (Aspect Oriented Programming) :⾯向切⾯编程,是⼀种思想,它是对某⼀类事情的集中处理。

举个例子:
当我们进行用户登录权限的校验,在需要进行校验的页面中,我们都各⾃实现或调⽤⽤户验证的⽅法,有了 AOP 之后,我们只需要在某⼀处配置⼀下,需要登录校验的页面就可以自主实现,不再需要每个方法中都写相同的登录校验。

AOP与Spring AOP的关系和IoC和DI类似,AOP是一种思想,而Spring AOP是一个具体的框架对AOP的实现。

2. Spring AOP的作用

对于以上的登录校验例子来说,我们使用Spring AOP我们可以减少代码的重复,提高我们程序员开发的效率,在具体开发中它可以实现以下功能:

  1. 统一日志记录
  2. 统一方法执行时间统计
  3. 统一的返回格式设置
  4. 统一的异常处理
  5. 事务开启和提交
  6. 统一登录校验等

对于我们对象来说,AOP扩展了它的能力,在某个方面我们可以说AOP是OOP(面向对象编程)的补充和完善,它们都是一种思想。

3.AOP的组成

  • 切⾯(Aspect):切⾯(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包括了连接点的定义。 在程序中就是一个处理某方面具体问题的类,类中包含很多方法,这些方法就是切点和通知。
  • 连接点(Join Point):应⽤执⾏过程中能够插⼊切⾯的⼀个点,这个点可以是方法调用时,抛出异常时或者修改字段时。切⾯代码可以利⽤这些点插⼊到应用的正常流程之中,并添加新的行为。它是可能会触发AOP的所有点(请求)。
  • 切点(Pointcut):切点是提供一组规则来匹配连接点,给满足规则的连接点添加通知。 切点就是用来进行主动拦截的规则(配置)然后触发AOP。
  • 通知(Advice):切面的工作被称为通知,定义了切⾯是什么,何时使用,描述了切⾯要完成的工作,还解决何时执行这个工作问题。也就是程序中被拦截请求触发的具体动作,在通知中的的具体业务代码。

通知的分类:使用注解可以实现

  • 前置通知:在执行目标方法之前执行的方法,@Before实现。比如我们要请求某页面要进行的登录检验相关方法,登录校验就是前置通知通过。请求页面的方法就是目标方法。
  • 后置通知:在执行目标方法之后执行的方法,通过@After实现。
  • 异常通知:在执行目标方法出现异常时执行的方法,通过@AfterThrowing实现。
  • 返回通知:目标方法执行了返回数据时(return)执行的通知,@AfterReturning实现。
  • 环绕通知:在目标方法执行的周期范围内(执行之前,执行中,执行后)都可以执行的。通过@Around实现。

4. Spring AOP的实现

4.1 添加Spring AOP依赖

首先创建一个Spring Boot项目,在创建过程中我们没有Spring AOP框架可选,需要在pom.xml文件中自己添加Spring AOP 依赖。
在这里插入图片描述

添加依赖,在Maven仓库中根据我们创建的spring boot项目添加以下依赖:
在这里插入图片描述

由于我使用的spring版本是2.7.13,所以我选用的版本也是2.7.13。

4.2 定义切面(创建切面类)

对于切面我使用的注解是@Component,让该类醉着框架启动。通过@Aspect表示该类是一个切面;

  1. package com.example.demo_aop.component;
  2. import org.aspectj.lang.annotation.Aspect;
  3. import org.springframework.context.annotation.EnableAspectJAutoProxy;
  4. import org.springframework.stereotype.Component;
  5. /**
  6. * @author zq
  7. * @date 2023-07-19 20:04
  8. */
  9. @Component
  10. @Aspect
  11. public class UserAspect {
  12. }

4.3 定义切点(配置拦截规则)

定义切点通过@Poincut注解,使用Aspect的表达式语法;该方法是空方法只起到表示作用,指向后面多个对应的通知。

  1. //定义切点,使用Aspect的表达式语法
  2. // 表示拦截该UserController下所有方法
  3. @Pointcut("execution(* com.example.demo_aop.controller.UserController.*(..))")
  4. public void poincut(){
  5. }
4.3.1 切点表达式语法

切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,语法为:

execution(<修饰符><返回类型> <包.类.方法(参数)><异常>)

*号可以匹配任意字符,只匹配一个元素如包、类、方法、方法参数;…符号可以匹配任意字符,多个元素,在表示类时,需要与 星号联合使用;+号表示按照类型匹配指定类的所有类,必须跟在类名后面。如com.example.User+,就表示继承该类的所有子类和本身。

** 注意:**

  1. 修饰符和异常通常可以省略,返回值不能省略。
  2. 在我们上述代码中的表达式就省略了修饰符,用*号表示返回值类型。
  3. 返回值与包是两个东西所以加上了空格
  4. 在我们上述代码表达式省略了异常。括号中的点点表示匹配任意参数的方法。

4.4 定义通知的实现

以下实现前置通知和后置通知;注解中对应切点的方法名。

  1. // 表示该通知针对该方法
  2. // 前置通知
  3. @Before("pointcut()")
  4. public void beforeAdvice(){
  5. System.out.println("执行力前置通知");
  6. }
  7. // 后置通知
  8. @After("pointcut()")
  9. public void AfterAdvice(){
  10. System.out.println("执行了后置通知");
  11. }

解释说明:我们不在切点中实现具体方法,是因为我们实现的方法有很多种,所以通过通知进行实现,它们具有1对多的关系。

在UserController类中创建方法检验AOP执行过程:

  1. package com.example.demo_aop.controller;
  2. import org.springframework.web.bind.annotation.RequestMapping;
  3. import org.springframework.web.bind.annotation.RestController;
  4. /**
  5. * @author zq
  6. * @date 2023-07-19 20:25
  7. */
  8. @RequestMapping("/user")
  9. @RestController
  10. public class UserController {
  11. @RequestMapping("/hi")
  12. public String sayHi(String name){
  13. System.out.println("执行了sayHi方法");
  14. return "Hi" + name;
  15. }
  16. @RequestMapping("/hello")
  17. public String sayHello(String name){
  18. System.out.println("执行了sayHello方法");
  19. return "Hello" + name;
  20. }
  21. }

如图当我们启动程序,访问http://localhost:8080/user/hi时,控制台输出结果符合AOP执行过程
在这里插入图片描述

同理我们可以在切面类中也实现环绕通知,指的注意的是我们在环绕通知中必须通过 object = joinPoint.proceed(); 才能执行目标方法,不然只是执行环绕通知 ;

  1. // 环绕通知
  2. @Around("poincut()")
  3. // 它必须有返回值返回给框架
  4. public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
  5. Object object = null;
  6. System.out.println("进入环绕通知");
  7. // 执行目标方法
  8. object = joinPoint.proceed();
  9. System.out.println("退出环绕通知");
  10. return object;
  11. }

执行结果如下:
在这里插入图片描述

5. Spring AOP实现原理

Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 的支持局限于方法级别的拦截。Spring AOP ⽀持 JDK Proxy 和 CGLIB 方式实现动态代理。默认情况下,实现了接⼝的类,使⽤ AOP 会基于 JDK 生成代理类,没有实现接口的类,会基于 CGLIB 生成代理类。

也就是说我们本来要访问某个对象,但是我们Spring AOP构造了一个对应的代理类,我们访问时会通过代理类来访问我们的目标对象,不能直接访问

如图所示:对于我们以上代码来说我们本来是访问UserController类,但是我们不能直接访问了,而是通过访问代理类访问。
在这里插入图片描述

两种代理方式的区别:

  1. JDK 实现,要求被代理类必须实现接⼝,之后是通过 InvocationHandler 及 Proxy,在运行时动态的在内存中⽣成了代理类对象,该代理对象是通过实现同样接⼝来实现,只是该代理类是在运行期时,动态的织⼊统⼀的业务逻辑字节码来完成。
  2. CGLIB 实现,被代理类可以不实现接⼝,是通过继承被代理类,在运⾏时动态的生成代理类对象。

发表评论

表情:
评论列表 (有 0 条评论,179人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Spring AOP介绍

    1、简介 spring提供了两个核心功能,一个是IoC(控制反转),另外一个便是Aop(面向切面编程),IoC有助于应用对象之间的解耦,AOP则可以实现横切关注点(如日志、

    相关 Spring:AOP简单介绍

    AOP基本概念: AOP,面向切面编程,是一种概念,是一种思想,其实现者有很多,Spring就是其一。 AOP,是ooP的一种补充,OOP是从静态角度考虑程序的结构,而

    相关 Spring AOP详细介绍

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。 一 AO

    相关 Spring AOP介绍

    什么是AOP 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维