Spring AOP

一. 什么是 Spring AOP

AOP: 面向切面编程,它是⼀种思想,它是对某⼀类事情的集中处理。

⽽ Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现

二. AOP 有什么用

1)对于一些功能统⼀,且使⽤的地⽅较多的功能,就可以考虑 AOP 来统⼀处理了(例如验证登录功能)

2)统⼀⽇志记录

3)统⼀⽅法执⾏时间统计

4)统⼀的返回格式设置

5)统⼀的异常处理

6)事务的开启和提交等

也就是说使用 AOP 可以扩充多个对象的某个能力,所以 AOP 可以 说是 OOP(Object Oriented Programming,⾯向对象编程)的补充和完善。

三. 学习 Spring AOP

3.1 AOP 组成

3.1.1 切面(Aspect)

  切⾯(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包 括了连接点的定义。

通俗来说,切面就是程序中处理某方面具体问题的一个类,类里面包含了很多方法,这些方法就是切点和通知

3.1.2 切点(Pointcut)

配置了主动拦截规则的方法

3.1.3 通知(Advice)

在通知中实现具体的业务代码,

1)前置通知使⽤ @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。

2)后置通知使⽤ @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤

3)返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。

4)抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。

5)环绕通知使⽤ @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为。

3.2 Spring AOP 实现

3.2.1 添加 AOP 框架支持 

在 pom.xml 中添加如下配置:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
   <version>2.7.1</version>
<!-- 此处版本应与自身的 Spring Boot 版本对应 -->
</dependency>

 3.2.2 定义切点和切面

@Aspect//切面类
@Component
public class UserAspect {

    // 切点
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut() { }
}
其中 pointcut 方法为空方法,它不需要有方法体,此方法名就是起到⼀个“标识”的作用,标识下面的通知方法具体指的是哪个切点(因为切点可能有很多个)。
切点表达式说明
AspectJ ⽀持三种通配符
* :匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数)
.. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤。
+ :表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如 com.cad.Car+ ,表示继承该类的 所有⼦类包括本身
切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,语法为:
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)
修饰符和异常可以省略,具体含义如下:

 

 3.2.3 定义相关通知

通知定义的是被拦截的⽅法具体要执⾏的业务
具体实现:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class UserAspect {

 // 定义切点⽅法
 @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
 public void pointcut(){ }

 // 前置通知
 @Before("pointcut()")
 public void doBefore(){
     System.out.println("执⾏ Before ⽅法");
 }

 // 后置通知
 @After("pointcut()")
 public void doAfter(){
     System.out.println("执⾏ After ⽅法");
 }

 // return 之前通知
 @AfterReturning("pointcut()")
 public void doAfterReturning(){
     System.out.println("执⾏ AfterReturning ⽅法");
 }

 // 抛出异常之前通知
 @AfterThrowing("pointcut()")
 public void doAfterThrowing(){
     System.out.println("执⾏ doAfterThrowing ⽅法");
 }
 
 // 添加环绕通知
 @Around("pointcut()")
 public Object doAround(ProceedingJoinPoint joinPoint){
     Object obj = null;
     System.out.println("Around ⽅法开始执⾏");
     try {
         // 执⾏拦截⽅法
         obj = joinPoint.proceed();
     } catch (Throwable throwable) {
         throwable.printStackTrace();
     }
     System.out.println("Around ⽅法结束执⾏");
     return obj;
 }
}

通过以上代码我们就实现了 Spring AOP 了

3.3 AOP 实现原理

Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 的⽀持局限于⽅法级别的拦截。
Spring AOP ⽀持 JDK Proxy 和 CGLIB ⽅式实现动态代理。默认情况下,实现了接⼝的类,使
⽤ AOP 会基于 JDK ⽣成代理类,没有实现接⼝的类,会基于 CGLIB ⽣成代理类
织入:代理的生成时机
织⼊是把切⾯应⽤到⽬标对象并创建新的代理对象的过程,切⾯在指定的连接点被织⼊到⽬标对 象中
在⽬标对象的⽣命周期⾥有多个点可以进⾏织⼊:
1)编译期
2)类加载期
3)运行期
动态代理
在 class 代码运⾏期,动态的织⼊字节码。
我们学习 Spring 框架中的AOP,主要基于两种⽅式:JDK CGLIB 的⽅式。这两种⽅式的代
理⽬标都是被代理类中的⽅法,在运⾏期,动态的织⼊字节码⽣成代理类
JDK 和 CGLIB 实现的区别
1. JDK 实现,要求被代理类必须实现接⼝,之后是通过 InvocationHandler 及 Proxy,在运⾏ 时        动态的在内存中⽣成了代理类对象,该代理对象是通过实现同样的接⼝实现(类似静态代理接        ⼝的⽅式),只是该代理类是在运⾏期时,动态的织⼊统⼀的业务逻辑字节码来完成。
2. CGLIB 实现,被代理类可以不实现接⼝,是通过继承被代理类,在运⾏时动态的⽣成代理类对      象。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值