Spring AOP —— 详解、实现原理、简单demo

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 Spring AOP —— 详解、实现原理、简单demo,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

目录

一、Spring AOP 是什么?

二、学习AOP 有什么作用?

三、AOP 的组成

3.1、切面(Aspect)

3.2、切点(Pointcut)

3.3、通知(Advice)

3.4、连接点

四、实现 Spring AOP 一个简单demo

4.1、添加 Spring AOP  框架依赖

4.2、定义切面

4.3、定义切点

4.3.1、切点表达式说明

4.4、定义通知

4.5、实现原理

​编辑  

五、Spring AOP 实现原理

5.1、原理概述

5.2、织入

5.3、动态代理

5.4、面试题:DK 和 CGLIB 实现的区别


一、Spring AOP 是什么?


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

例如登陆权限的检验(检测当前用户是否登录),在学习 AOP 前,我们会将这样一个检测机制封装成一个方法,在需要检测的地方调用该方法即可,但想象以下,首先,如果这个方法有 1000 个地方要进行调用, 那么你去一个一个写调用函数很累,其次,一旦这个登陆检查方法需要修改,比如增加一个参数,那么,你就需要修改 1000 方法调用的参数… 但如果你会 AOP 后,我们只需要在某处配置一下,就可以实现用户的登录检测,不需要每一个方法中都写登录检验的调用方法啦! 

AOP 是一种思想,而 Spring AOP 是一个框架,提供了对 AOP 思想的实现(类似于 IoC 和 DI 的关系)。

二、学习AOP 有什么作用?


例如刚刚我们所讲到的登录检测机制,这一个方法一旦需要调用的地方多了,不仅写起来麻烦,维护起来成本也是很高的,所以,对于这种功能统一,且使用地方较多的功能,就可以考虑 AOP 来进行统一的处理!

例如以下常见的使用场景:

  • 统一登录检测机制。
  • 统一方法的执行时间统计。
  • 统一的返回格式设置。
  • 统一异常处理。
  • 事务的开始和提交。

Ps: AOP 是对某一功能进行的统一处理,大大降低了代码维护的成本,所以可以说 AOP 是 OOP 的补充和完善~

三、AOP 的组成


3.1、切面(Aspect)

切面,在程序中就是对某一功能进行统一处理的, 这个类里包含了很多方法,这些方法就是由 切点通知 组成。

3.2、切点(Pointcut)

用来进行主动拦截的规则(配置)。

这里拦截的是什么,过程是什么样的呢?就是对用户向服务器发送的请求进行拦截,检测用户的操作是否符合预期,发现问题并统一处理的过程,如下图:

Spring AOP —— 详解、实现原理、简单demo

 

3.3、通知(Advice)

通知就是 AOP 的具体执行动作。具体的,在程序中被拦截后会触发一个具体的动作,就是通知中具体实现的业务代码

在 Spring 中,可以在方法上使用以注解,设置方法为通知方法,被拦截后满足条件就会调用通知方法:

  • 前置通知(@Before):执行 目标方法(被拦截的方法)之前执行的方法。
  • 后置通知(@After):执行了目标方法之后执行的方法。
  • 返回之后通知(@AfterReturning):目标方法执行了返回数据(return)时,执行的方法。
  • 抛异常后通知(@AfterThrowing):在执行目标方法出现异常时,执行的方法。
  • 环绕通知(@Around):在目标方法执行的周期范围内(执行之前,执行中,执行后)都可以执行的方法(Ps:如果已经有了前置和后置通知,再使用环绕通知,那么周期范围就在前置通知之前 ~ 后置通知之后)。

3.4、连接点

会触发 AOP 规则的所有的点(所以请求)。

四、实现 Spring AOP 一个简单demo


4.1、添加 Spring AOP  框架依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

Ps:

1.创建 Spring Boot 项目时是没有 Spring AOP 框架可以选择的。

2.添加  Spring AOP 框架可以去中央仓库,值得注意的是要选择 Spring Boot 对应的 AOP ,而不是 Spring 对应的 AOP。

3.最好选择 Spring Boot 对应版本的  AOP ,以上就是 2.7.9版本。

4.2、定义切面

使用 @Aspect 注解修饰类,告诉框架是一个切面类。

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


@Aspect //告诉框架我是一个切面类
@Component
public class UserAspect {

}

4.3、定义切点

使用 @Pointcut 修饰一个方法,它不需要由方法体。方法名就是起到一个标识的作用,标识通知方法具体指的是哪一个切点(切点可能有多个)。

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() {
    }

}

4.3.1、切点表达式说明

AspectJ ⽀持三种通配符,如下:

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

切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,语法如下(注意使用空格进行分割):

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

其中,修饰符和异常可以省略,具体含义如下:

Spring AOP —— 详解、实现原理、简单demo

 

4.4、定义通知

使用通知方法中的五个注解,其中前置通知、后置通知、环绕通知最常用,那么以下代码我将用这三个注解来举例:

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 beforeAdvice() {
        System.out.println("执行了前置通知");
    }

    /**
     * 后置通知
     */
    @After("pointcut()")
    public void aftereAdvice() {
        System.out.println("执行了后置通知");
    }

    /**
     * 环绕通知
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("pointcut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("进入了环绕通知~");
        Object obj = null;
        obj = joinPoint.proceed();
        System.out.println("退出了环绕通知~");
        return obj;
    }

}

执行结果如下:

Spring AOP —— 详解、实现原理、简单demo

4.5、实现原理

Spring AOP —— 详解、实现原理、简单demo  

五、Spring AOP 实现原理


5.1、原理概述

Spring 的切面是代理类实现的,包裹了目标对象,也就是说,用户只能先通过代理类,进行校验,如果没有问题才会进一步访问到目标对象。

Spring AOP —— 详解、实现原理、简单demo

5.2、织入

织入简单理解就是代理生成的时机,一般情况下,在 Spring AOP 动态代理的植入时机是程序的运行期。

5.3、动态代理

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

Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理。默认情况下,实现了接口的类,使用 AOP 会基于 JDK 生成代理类,没有实现接口的类,会基于 CGLIB 生成代理类。

JDK 和 CGLIB 底层都是基于反射实现的。、

5.4、面试题:DK 和 CGLIB 实现的区别

1. JDK 实现,要求被代理类必须实现接⼝,之后是通过 InvocationHandler 及 Proxy,在运⾏ 时动态的在内存中⽣成了代理类对象,该代理对象是通过实现同样的接⼝实现(类似静态代理接⼝实现的⽅式),只是该代理类是在运⾏期时,动态的织⼊统⼀的业务逻辑字节码来完成。

2. CGLIB 实现,被代理类可以不实现接⼝,是通过继承被代理类,在运⾏时动态的⽣成代理类对象。

Spring AOP —— 详解、实现原理、简单demo

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129783.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!