目录
Spring AOP 的原理,也就是Spring底层是如何实现AOP的?
IOC:控制反转
Ioc概念
先来说说IOC:IOC是一种思想。 控制反转,即对对象的控制权发生反转。即获取依赖对象的过程发生了反转。感觉就是传参的时候不再是单单传某个变量,而是直接传所要依赖的对象。这样不会再因为一处地方要增加参数或减少参数,而影响其它代码。耦合度降低。
Ioc的优点
- 集中管理
- 解耦合
Spring Ioc
Spring Ioc 则是实现了这种思想,获取依赖对象时 Spring Ioc 帮我们对对象做了管理。我们不再需要手动new对象,而是用的时候从Spring容器中取即可,即DI(依赖注入)。Spring ioc 可以理解为是 一个容器,可以用来存取对象。对对象的生命周期的控制权由程序员交给了Spring来管理。
对对象的控制权发生了变化,由之前的开发人员手动new对象,变为由Spring框架帮我们来管理对象,用的时候对象直接依赖注入(DI)。
DI(依赖注入)
- 注入方式:构造器注入
- 依赖:即bean对象的创建依赖于容器
- 注入:即bean对象中所有的属性,由容器来注入。
AOP:面向切面编程
AOP是一种思想,是对一类事物的集中处理。比如:登录拦截请求,统一异常,同一结果返回等。而拦截器就是AOP的一种具体实现。AOP作用的维度更加细致(可以根据包、类、方法名、参数等进行拦截),能够实现更加复杂的业务逻辑。简单来说就是,AOP的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。AOP就是代理模式的典型应用。Spring AOP就是AOP的一种实现方式,还有AspectJ,CGLIB。
AOP的优点
- 代码无入侵:不修改原始的业务方法,就可以对原始的业务方法进行功能的增强或者是功能的改变 。即解耦合。
- 减少了重复代码 。
- 提高开发效率 。
- 维护方便。
Spring AOP
1.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.核心概念
- 1.切点(PointCut):提供一组规则(切点表达式),告诉程序对哪些方法进行功能增强
- 2.连接点(Join Point): 满足切点表达式规则的方法,就是连接点
- 3.通知(Advice):对满足切点表达式的方法具体要做哪些事,比如下面的记录方法执行耗时
- 4.切面(Aspect):切面=切点+通知
切点和连接点的关系:切点就是满足切点表达式的所有方法,一个保存了许多连接点的集合,而连接点就是某一个方法,集合中的一个元素。
举例:全体同学上课
那切点就是:全体同学
连接点就是:张三,李四,某一个同学,其实就是执行目标方法
通知就是:上课
切面就是:整个定义的aop方法
- @Aspect:标识声明这是⼀个切面类
- @Around:环绕通知,在目标方法的前后都会被执行,后面的表达式表示对哪些方法进行增强
- PrceedingJoinPoint.proceed()让原始方法执行
如下为记录一个方法执行耗时
@Aspect //声明该类为切面类
@Slf4j
@Component
@Order(2) //指定多个类的执行次序 值越小,优先级越高
//比如记录一个接口的执行时间
public class TestAspect {
@Around("execution(* com.example.demo.controller.UserController.*.*(..))") //切点 生效
的范围 具体即某个接口,类或者包 自定义 切点表达式
public Object record(ProceedingJoinPoint pj) { // pj 连接点
/**
* 以下为通知
*/
// 记录开始时间
long start = System.currentTimeMillis();
// 目标方法执行 以下为标准写法
Object result = null;
try {
result = pj.proceed(); //执行原方法
} catch (Throwable e) {
log.error(pj.toShortString()+"发生异常,e:",e);
}
// 日志打印切点执行时间
log.info(pj.getSignature()+"cost time:"+(System.currentTimeMillis()-start)+"ms");
return result;
}
}
3.通知的类型
- @Around:环绕通知,此注解标注的通知方法在目标方法前,后都被执行
- @Before:前置通知,此注解标注的通知方法在目标方法前被执行
- @After:后置通知,此注解标注的通知⽅法在目标方法后被执行,无论是否有异常都会执行
- @AfterReturning:返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
- @AfterThrowing:异常后通知,此注解标注的通知方法发生异常后执行
由上执行结果可知,执行顺序为:
1.当目标方法执行无异常时:
2.当目标方法执行有异常且throws,往出抛时: