我们先了解以下什么是AOP。AOP(Aspect Oriented Programming): 面向切面编程,它是一种思想,它是对一类事情的集中处理。比如:我们在创建购物网站的时候,我们的查看商品,购买商品等页面需要进行登录校验,我们可以把每个页面进行登录校验的操作进行集中的处理。Spring AOP是AOP的一种实现形式。
对于像用户登录校验的功能,在一个程序的很多地方会使用到,我们可以考虑AOP来进行统一的处理。
除了统一的用户登录判断以外,AOP还可以实现:
Spring AOP学习主要分为以下三个部分:
【切面】
切面由切点和通知组成,它既包含了横切逻辑的定义,也包含了连接点的定义。
【连接点】
用用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时
前面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
连接点相当于需要增强的某个AOP功能的所有方法
【切点】
作用是提供一组规则来匹配连接点,满足规则的连接点添加通知。
【通知】
切面也是有它们的目标的——它必须完成它的任务,这个任务被称为通知
通知:定义了切面是什么,何时使用,以及描述了切面要完成的工作,还解决了何时执行这个工作的问题。
Spring切面类中,可以在方法上使用以下数据,会设置方法为通知方法,在满足条件后会通知本方法进行调用:
接下来,我们使用Spring AOP来实现下AOP的功能,完成的目标是拦截所有UserController里面的方法,每次调用UserController中任意一个方法时,我们执行相应的通知事件。
Spring AOP的实现步骤如下:
在pom.xml中添加如下配置:
org.springframework.boot
spring-boot-starter-aop
切点指的是具体要处理的一类问题,比如用户登录权限的校验,就是一个具体的问题,记录所有方法执行日志就是一个具体的问题,切点定义的是一类问题。
我们先准备下,接下来会用到的代码
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/hi")
public String getHi() {
return "hi";
}
@RequestMapping("/name")
public String getName() {
return "name";
}
@RequestMapping("password")
public String getPassword() {
return "password";
}
}
Spring AOP切点定义如下,在切点中我们要定义拦截的规则,具体实现如下:
@Aspect //定义此类是是一个切面
@Component
public class UserAspect {
//定义切点,这里使用了AscpectJ表达式语法
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut(){}
}
切点表达式说明:
切点表达式由切点函数组成,其中execution()是常见的切点函数,语法为:
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)
表达式实例:
execution(* com.cad.demo.User.*(..)):匹配User类下的所有方法;
execution(* com.cad.demo.User+.*(..):匹配User类的子类的所有方法;
通知定义的是被拦截的方法具体要执行的业务,比如用户登录权限验证方法。Spring AOP中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件以后会通知本方法进行调用:
具体实现如下:
@Aspect //定义此类是是一个切面
@Component
public class UserAspect {
//定义切点,这里使用了AscpectJ表达式语法
@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 doAfterReturn() {
System.out.println("执行了AfterReturn方法");
}
//抛出异常之前通知
@AfterThrowing("pointcut()")
public void doAfterThrowing() {
System.out.println("执行了AfterThrowing方法");
}
//添加环绕方法
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) {
Object obj = null;
System.out.println("Around方法开始执行");
try {
//执行拦截方法
obj=joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("Around方法执行结束");
return obj;
}
}
Spring AOP是构建在动态代理基础上,因此Spring对AOP的支持局限于方法级别的拦截。
Spring AOP支持 JDK Proxy和CGLIB方法实现动态代理。默认情况下,实现了接口的类,使用AOP会基于JDK生成代理类,没有实现接口的类,会基于CGLIB类
JDK和CGLIB实现的区别
AOP是对某方面能力的统一实现,它是一种思想,Spring AOP是对AOP的具体实现
Spring AOP的实现步骤:
Spring AOP是通过动态代理的方式,在运行期间将AOP代码织入到程序中,它的实现方式有两种:JDK Proxy和CGLIB