目录
Spring AOP概念
AOP适用场景
AOP 组成
1、切面(Aspect)
2、切点(Pointcut)
3、通知(Advice)
4、连接点(Join Point)
Spring AOP实现
添加AOP框架依赖
定义切面和切点
AspectJ表达式说明
定义通知
SpringAOP的原理
织入(代理的生成时机)
动态代理
JDK 及 CGLIB 的方式的异同点
AOP :面向切面编程,它是⼀种思想,它是对某⼀类事情的集中处理。
就比如说在进行登录注册界面验证时,凡是需要使用到注册登录的方法,都需要添加登录注册验证代码。
因此在使用AOP之后,我们只需要在某⼀处配置⼀下,所有需要判断⽤户登录⻚⾯(中的方法)就全部可以实现⽤户登录验证了,不再需要每个⽅法中都写相同的⽤户登录验证了。
Spring AOP :AOP 是一种思想,而Spring AOP是一个框架,实现了对AOP思想的实现。
对于一些功能统一而且许多地方需要经常使用,这时候就可以使用AOP来进行统一进行处理了。
AOP的实现功能:
1.统一的用户登录注册判断
2.统一日志记录
3.统一方法执行时间统计
4.统一返回格式设置
5.统一的异常处理
6.事务的开启和提交等
AOP相当于是一个拦截器,需要经过AOP的验证才可访问服务器,效果图如下:
用来进行主动拦截的规则(配置)
切点相当于保存了众多连接点的⼀个集合(如果把切点看成⼀个表,⽽连接点就是表中⼀条⼀条 的数据)
切面所需要完成的工作就是通知。
通知:定义了切⾯是什么,何时使⽤,其描述了切面要完成的⼯作,还解决何时执行这个工作的问题。
常见的通知注解如下:
进入中央仓库官网:https://mvnrepository.com/ 并在搜索框中搜索AOP
在项目中pom.xml查看自己的Spring Boot项目版本
2.7.12版本的AOP依赖
org.springframework.boot
spring-boot-starter-aop
2.7.12
定义切面
@Aspect //告诉框架是一个切面
@Component //随着框架启动而启动
public class UserAspect {
}
定义切点
/*
* 切点(配置拦截规则)
* */
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut(){
}
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)
注意:返回类型与包之间用一个空格隔开
示例: execution(* com.cad.demo.User.*(..)) :匹配 User 类里的所有方法
修饰符(一般省略):
public 公共方法
* 任意
返回类型(一般不省略):
void 返回没有值
String 返回值字符串
* 任意
包:(一般情况下要有但是可以省略)
- com.gyf.crm 固定包
- com.gyf.crm.*.service crm包下面子包任意 (例如: com.gyf.crm.staff.service)
- com.gyf.crm.. crm包下面的所有子包 (含自己)
- com.gyf.crm.*.service.. crm包下面任意子包,固定目录service,service目录任意包
类(一般情况下要有但是可以省略):
UserServicelmpl 指定类,
*Impl 以Impl结尾,
User 以User开头
* 任意
方法名(不可省略):
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意
参数:
() 无参
(int) 一个参数
(int,int) 两个参数
(..) 任意参数
异常:throws 一般省略。
定义通知代码:
package com.example.demo.AOP;
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 afterAdvice(){
System.out.println("执行了后置通知~");
}
/*
* 环绕通知*/
@Around("pointcut()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("进入了环绕通知~");
Object obj = null;
obj = joinPoint.proceed();
System.out.println("退出环绕通知~");
return obj;
}
}
拦截代码:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class UserController {
@RequestMapping("/hi")
public String sayHi(String name){
System.out.println("执行了sayHi方法");
return "hi," + name;
}
}
运行启动类
Spring AOP 是构建在动态代理基础上,因此 Spring 对 AOP 支持局限于方法级别的拦截,Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理
我们在前后端交互的时候没有代理的时候前后端是直接进行交互的,但是这样我们就需要去校验前端的一些数据等,如果我们有代理的话那么前端会先将数据传到代理代理做一个处理然后代理再将数据给后端,如此一来我们就可以专注于代码逻辑了。
织⼊是把切⾯应⽤到⽬标对象并创建新的代理对象的过程,切⾯在指定的连接点被织⼊到⽬标对象中。
在⽬标对象的⽣命周期⾥有多个点可以进⾏织⼊:
动态代理指的是在程序运行时动态地创建一个实现特定接口或一组接口的对象,该对象可以拦截并处理所有传递给它的方法调用。动态代理通常是通过在运行时生成字节码来实现的,从而避免了在编译时手工编写代理类的繁琐过程。
我们学习 Spring 框架中的AOP,主要基于两种⽅式:JDK 及 CGLIB 的⽅式。这两种⽅式的代理⽬标都是被代理类中的⽅法,在运⾏期,动态的织⼊字节码⽣成代理类。
相同点:
都可以在运行时动态生成代理对象,在代理对象中调用委托类的方法。
区别: