目录
AOP
为什么使用AOP
Spring AOP
AOP的组成
实现Spring AOP
AOP表达式
Spring AOP的实现原理
在介绍Spring AOP之前需要先介绍AOP
AOP
AOP(面向切面编程)就像我们之前学习的OOP(面向对象编程)它是一种思想,它是对某一类事情的集中处理,比如用户登录的校验,在没学AOP之前,需要判断用户是否登录的页面都需要各自实现用户验证的方法,然而在有了AOP之后我们只需要在某处配置,所有需要验证判断用户登录状态的页面就可以实现用户登录验证了,不需要每个方法都写相同的用户验证了
为什么使用AOP
在上面我举出登录校验的例子,如果没使用AOP那么所有需要登录校验的地方都需要进行判断,此时代码的维护成本就会越来越高,对于这种功能统⼀,且使用的地方较多的功能就需要使用AOP来统一处理
除了统一用户登录判断之外AOP还有其他作用
1.统一日志记录
2.统一方法执行时间统计
3.统一异常处理
4.统一的返回格式设置
5.事务的开启和提交等
可以说使用AOP是扩充多个对象的某个能力,所以AOP是OOP的补充和完善
Spring AOP
我们知道AOP是思想而Spring AOP则是Spring 公司对于AOP实现的具体方案
AOP的组成
1.切面(Aspect) : 定义AOP业务类型的(当前AOP是干嘛的)
2.连接点(Join Point): 程序中有可能调用AOP的地方就叫做一个连接点
3.切点(Pointcut): 定义AOP的拦截规则
4.通知(Advice): [增强方法] 定义什么时候做什么事
a.前置通知:拦截的目标方法之前执行的通知
b.后置通知:拦截的目标方法之后执行的通知
c.返回之后通知:拦截的目标方法返回数据之后的通知
d.抛出异常之后通知:拦截的目标方法抛出异常之后执行的通知
e.环绕通知:拦截的目标方法执行前后都会执行的通知
基础知识介绍比较难懂,我画图介绍方便理解
实现Spring AOP
1.添加Spring AOP框架支持
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.定义切面和切点
@Component
@Aspect //标识当前类为切面
public class LoginAOP {
//定义切点(拦截规则)
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut() {
}
}
3.定义通知
//前置通知
@Before("pointcut()")
public void before() {
System.out.println("执行了前置通知");
}
以上三步就是最基础的Spring AOP使用,下面检验一下效果
可以看到通过切点定义的拦截规则成功拦截到UserController包下的类并执行了前置方法
//环绕通知
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) {//参数是默认的代表正在执行的目标方法
Object result=null;
System.out.println("Around方法开始执行");
try {
result=joinPoint.proceed();//执行的目标方法
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("Around方法执行完成");
return result;
}
前面的四种通知都是方便理解的,这里强调环绕通知的使用,首先方法有参数代表要执行的目标方法
并且有返回值,其次就是通过joinPoint.proceed()方法执行目标方法,但不代表返回值是目标方法的返回值而是当前执行的目标方法
环绕通知执行最早结束最晚,在之中执行各种通知方法
AOP表达式
Spring AOP的实现原理
可以看到在没有代理类时我们是直接调用目标对象,当出现了代理之后就需要先经过代理才能调用目标对象,根据代理类产生的时机就可分为动态代理或者静态代理,我们学习的Spring AOP就是基于动态代理
Spring AOP支持 JDK Proxy 和 CGLIB 方式实现动态代理,当目标对象实现了接口就会使用JDK提供的Proxy ,当没有实现接口则基于CGLIB生成代理类