Spring AOP

目录

1. 什么是Spring AOP

2. AOP的组成

2.1 切面(Aspect)

2.2 连接点(Join Point)

2.3 切点(Pointcut)

2.4 通知(Advice)

3. Spring AOP的实现

3.1 添加Spring AOP框架支持

3.2 定义切面和切点以及通知

4. Spring AOP的实现原理


1. 什么是Spring AOP

        AOP(Aspect Oriented Programming):面向切面回答,它是⼀种思想,它是对某⼀类事情的集中处理。比如用户登录权限的效验,没学 AOP 之前,我们所有需要判断用户登录的页面(中的方法),都要各自实现或调用用户验证的方法,然而有了 AOP 之后,我们只需要在某⼀处配置⼀下,所有需要判断用户登录页面(中的方法)就全部可以实现用户登录验证了,不再需要每个方法中都写相同的用户登录验证了。

AOP是一种思想,而Spring AOP是一个框架,提供了对AOP思想的实现.就相当于IOC和DI类似.

AOP除了统一的登录判断之外,AOP还就可以实现:

Spring AOP_第1张图片

2. AOP的组成

1. 切面

2. 切点

3. 连接点

3. 通知

Spring AOP_第2张图片

2.1 切面(Aspect)

        切面由切点和通知组成,即包含了横切逻辑的定义,页包括了连接点的定义.

        切面是包含:通知,切点和切面的类,相当于AOP实现的某个功能的集合.

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

2.2 连接点(Join Point)

        应用执行过程中能够插⼊切面的⼀个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

        通俗的来说: 有可能触发拦截规则(AOP规则)的所有点(就是所有的请求)

2.3 切点(Pointcut)

        切点就是一种规则,用来匹配连接点,当连接点符合切点的规则的时候就会给这个连接点进行添加通知.

        通俗的来说:切点的作用:进行主动拦截的规则,承上启下,匹配连接点,添加通知

2.4 通知(Advice)

         切面也是有目标的 ——它必须完成的工作。在 AOP 术语中,切面的工作被称之为通知。

         通俗的来说:主动进行拦截,拦截成功执行的方案就是通知. === AOP具体的处理动作 

通知的执行,可以分为五种.

  • 1. 前置通知:  @Before
  • 2. 后置通知:  @After
  • 3. 返回之后通知:  @AfterReturning
  • 4. 抛异常后通知:  @AfterThrowing
  • 5. 环绕通知:  @Around

3. Spring AOP的实现

        接下来我们使⽤ Spring AOP 来实现⼀下 AOP 的功能,完成的目标是拦截所有 UserController 里面的方法,每次调用UserController 中任意⼀个方法时,都执行相应的通知事件。Spring AOP 的实现步骤如下:

3.1 添加Spring AOP框架支持


			org.springframework.boot
			spring-boot-starter-aop

3.2 定义切面和切点以及通知

我们创建一个类,给这个类进行添加@Aspect(表示这是一个切面)@Component(表示这个类随着Spring的启动而启动)

1. 创建切面

2. 构造切点

以上我们定义了拦截的规则,表示我们将拦截com.example.demo.controller.UserController这个类中的所有方法

切断点的表达式说明:

AspectJ 支持三种通配符
* :匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数)
.. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使用。
+ :表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如 com.cad.Car+ ,表示继承该类的所有子类包括本身

Spring AOP_第3张图片

execution(* com.cad.demo.User.*(..)) :匹配 User 类里的所有方法。
execution(* com.cad.demo.User+.*(..)) :匹配该类的子类包括该类的所有⽅法。
execution(* com.cad.*.*(..)) :匹配 com.cad 包下的所有类的所有方法。
execution(* com.cad..*.*(..)) :匹配 com.cad 包下、子孙包下所有类的所有方法。
execution(* addUser(String, int)) :匹配 addUser 方法法,且第⼀个参数类型是 String,第⼆个参数类型是 int。

3. 定义通知

Spring AOP_第4张图片

以上是定义了两个简单的通知,我们平常使用的是环绕通知

Spring AOP_第5张图片

 完整代码:

package com.example.demo.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: YAO
 * Date: 2023-07-13
 * Time: 19:18
 */
// 1. 定义切面
@Aspect     // 表示当前类是一个切面
@Component  // 当前类随着Spring的启动而启动
// 两个注解缺一不可
public class UserAspect {
    // 2.定义切点
    // 使用注解@Pointcut 加 AspectJ 表达式语法 定义拦截规则
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    //拦截这个目录下的所有方法 com.example.demo.controller.UserController.
    public void pointCut(){
    }

    // 4.定义通知
    // 通知一定要对应相应的岚切规则,一个拦截规则可以执行多个通知
    // 4.1 执行前通知
    // @before()参数:针对拦截规则的方法名
    @Before("pointCut()")
    public void doBefore(){
        System.out.println("执行前置通知");
    }

    // 4.2 执行后通知
    @After("pointCut()")
    public void doAfter(){
        System.out.println("执行后置通知");
    }

    // 4.3 环绕通知
    @Around("pointCut()")
    // 环绕通知必须要有返回值,交给框架进行下一步操作
    public Object doAround(ProceedingJoinPoint joinPoint){
        Object object = null;
        System.out.println("Around ⽅法开始执⾏");

        try {
            object = joinPoint.proceed();
        } catch (Throwable e ) {
            e.printStackTrace();
        }
        System.out.println("Around ⽅法结束执⾏");
        return object;
    }
}

 浏览器进行发送请求

控制台进行打印 

Spring AOP_第6张图片

4. Spring AOP的实现原理

Spring AOP 是构建在动态代理的基础上的,因此Spring对AOP的支持局限于方法级别的拦截.

那么什么是动态代理呢?

动态代理:就不进行直接访问,通过代理的方式进行访问

举例: 访问国外网站,国内无法直接进行访问,我们可以通过添加代理的方式进行访问,使用国外的服务器进行转发请求进行访问.

 

AOP就是构建在动态代理的基础之上的,就是通过使用切点设置拦截规则,使得用户不能直接访问,而是必须进行访问切点这个代理才能,进行验证之后进行访问.

Spring AOP_第7张图片

动态代理在Spring AOP中有两种:

1.JDK Proxy (默认情况下实现接口的类使用)

2.CGLIB (没有实现接口的类会基于这种方式生成代理类)

织入: 代理的生成时机.

Spring AOP生成代理的时机是在运行,就是切面在应用运行的某一时刻被织入,一般请开你改下,在织入切面的时候,AOP容器回味目标对象动态的创建一个代理对象.

JDK 和 CGLIB 实现的区别

 

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

3. Spring中默认使用jdk动态代理  SpringBoot进行了改进默认使用CGLIB

 

你可能感兴趣的:(#,Spring,AOP,spring,java,后端)