目录
[1.什么是Spring AOP](#1.什么是Spring AOP)
[4.Spring AOP的实现](#4.Spring AOP的实现)
前言:
在上一节中小编主要是于大家分享了有关于MyBatis的一些基础知识,让大家了解了有关于如何将数据库和我们的程序进行关联,那么接下来我们就来一起来学一下有关于AOP的一些知识,在Spring中一般提到的就是IoC和AOP,那么之前的学习中也给大家介绍了有关于IoC容器的一些基础知识,那么接下来小编将会带着大家一起来学习有关于AOP的一些基础知识。这节中小编将主要介绍有关于AOP的组成,概念,学习Spring AOP的使用以及Spring AOP的实现原理。
1.什么是Spring AOP
在介绍Spring AOP之前,首先我们需要了解一下什么是AOP?
**AOP(Aspect Oriented Programming):面向切面编程,它是一种思想,它是对某一类事情的集中处理。**比如用户登录权限的校验,没学AOP之前,我们所有需要判断用户登录的页面(中的方法),都要各自实现或调用用户验证的方法,然而有了AOP之后,我们只需要在某一处配置一下,所有需要判断用户登录页面中的方法就全部可以实现用户登录验证了,不再需要每个方法中都写相同的用户登录验证了。

**那么对于AOP与Spring AOP之间的关系就是:**AOP是一种思想,而Spring AOP是一个框架,提供了一种对AOP思想的实现,它们的关系和IoC与DI类似。
2.为什么要使用AOP呢?
想象⼀个场景,我们在做后台系统时,除了登录和注册等几个功能不需要做⽤户登录验证之外,其他几乎所有⻚⾯调⽤的前端控制器( Controller)都需要先验证⽤户登录的状态,那这个时候我们要怎么处理呢?
我们之前的处理⽅式是每个 Controller 都要写⼀遍⽤户登录验证,然⽽当你的功能越来越多,那么你要 写的登录验证也越来越多,⽽这些⽅法⼜是相同的,这么多的⽅法就会代码修改和维护的成本。那有没有简单的处理⽅案呢?答案是有的,对于这种功能统⼀,且使⽤的地⽅较多的功能,就可以考虑 AOP 来统⼀处理了。
除了统⼀的⽤户登录判断之外,AOP 还可以实现:
- 统⼀⽇志记录
- 统⼀⽅法执⾏时间统计
- 统⼀的返回格式设置
- 统⼀的异常处理
- 事务的开启和提交等
也就是说使⽤ AOP 可以扩充多个对象的某个能力,所以 AOP 可以 说是 OOP(Object Oriented
Programming,⾯向对象编程)的补充和完善。
3.AOP的组成
3.1切面
切面(Aspect):它是定义事件(表明AOP是做啥的)。比如现在要做一个用户的登录校验。他就像是一个公司的老板一样来定义公司的方向。
3.2切点
切点(Pointcut):它是用来定义具体规则的。在上面切面明确了要做的是用户的登录校验之后接下来就由切点来定义用户登录拦截规则,哪些接口判断用户登录权限。哪些不判断。就像是公司中的中层领导人一样制定一份具体的方案。
3.3通知
通知(Advice):AOP执行的具体方法。在前俩个的基础之上方向明确,方案已经制定好之后,那么接下来就需要实施了,获取用户登录的信息,如果获取到说明已经登录,否则未登录。他就是公司的底层,用来负责具体业务的执行。
在Spring切面类中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件之后会通知本方法进行调用:
- 前置通知: 使用**@Before**,通知方法会在目标方法调用之前执行。
- 后置通知: 使用**@After**,通知方法会在目标方法返回或者抛出异常后调用。
- 返回通知: 使用**@AfterReturning**,通知方法会在目标方法返回后调用。
- 异常通知: 使用**@AfterThrowing**,通知方法会在目标方法抛出异常之后调用。
- 环绕通知: 使用**@Around**,通知包裹了被通通知的方法,在被通知的方法之前和调用方法之后执行自定义的行为。
3.4连接点
连接点( Join Point):有可能触发切点的所有点。比如说是在登录功能中会触发登录功能的所有接口。
AOP整个组成部分的概念如下图所示:
4.Spring AOP的实现
先来定义一个UserController。
java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/getuser")
public String getUser() {
System.out.println("do getUser");
return "get user";
}
@RequestMapping("/deluser")
public String delUser() {
System.out.println("do delUser");
return "del user";
}
}
4.1添加依赖
在pom.xml中添加如下配置。
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

4.2定义切面

4.3定义切点

4.4实现通知
当我们输入一下url的时候:
就会在控制台中输出前置通知。
当加上后置通知的时候就会如下所示:
后置通知的代码:

此时在输入url之后的效果就是:

那么如果加的是环绕通知的效果呢?
环绕通知的代码如下所示:

执行结果如下所示:

那么如果没有上述的这些拦截的话,在实现过程当中就不会执行任何其他操作,比如我们现在定义一个ArticleController,如下所示:
java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/art")
public class ArticleController {
@RequestMapping("/getart")
public String getArticle(){
System.out.println("do getArticle");
return "getArticle";
}
}
当我们在访问的是后台就只会执行它本身要执行的方法。


5.AOP的实现原理
Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 的⽀持局限于⽅法级别的拦截。
Spring AOP ⽀持 JDK Proxy 和 CGLIB⽅式实现动态代理。默认情况下,实现了接⼝的类,使用 AOP 会基于 JDK ⽣成代理类,没有实现接⼝的类,会基于 CGLIB ⽣成代理类。
Spring 动态代理的组成:
- JDK Proxy:代理对象必须实现接口,才能使用JDK Proxy。
- CGLIB:通过实现代理类的子类来实现动态代理,注意被final修饰的类是不能够被代理的。
JDK Proxy 与 CGLIB的区别:
- 出生不同。
- **实现不同:**JDK Proxy要求代理类实现接口才能实现代理;而CGLIB是通过实现代理类的子类来完成动态代理的。
- **性能不同:**JDK& + JDK Proxy性能是略高于CGLIB;JDK7之前CGLIB性能高于JDK Proxy。
结束语:
好了这节小编就给大分享到这里啦,希望这节对大家有关于Spring AOP的基础知识的了解有一定帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)
