一、什么是AOP
AOP:Aspect Oriented Programming,中文翻译为”面向切面编程“。面向切面编程是一种编程范式,它作为OOP面向对象编程的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、权限控制、缓存控制、日志打印等等。AOP采取横向抽取机制,取代了传统纵向继承体系的重复性代码。
Spring主要有两大功能,IOC(控制反转)与AOP(面向切面编程)。Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。
二、AOP相关概念
(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
三、各注解说明
(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可
(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值
(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名
来访问目标方法中所抛出的异常对象
(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式
(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint
四、执行顺序
情况一: 一个方法只被一个Aspect类拦截
正常情况:
异常情况:
情况二: 同一个方法被多个Aspect类拦截
五、相关依赖及测试代码
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency>
package com.recruit.config.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component @Aspect public class Operator { @Pointcut("execution(* com.recruit.controller.LoginController.*(..))") public void pointCut() { } @Before("pointCut()") public void doBefore(JoinPoint joinPoint) { System.out.println("AOP Before Advice..."); } @After("pointCut()") public void doAfter(JoinPoint joinPoint) { System.out.println("AOP After Advice..."); } @AfterReturning(pointcut = "pointCut()", returning = "returnVal") public void afterReturn(JoinPoint joinPoint, Object returnVal) { System.out.println("AOP AfterReturning Advice:" + returnVal); } @AfterThrowing(pointcut = "pointCut()", throwing = "error") public void afterThrowing(JoinPoint joinPoint, Throwable error) { System.out.println("AOP AfterThrowing Advice..." + error); System.out.println("AfterThrowing..."); } @Around("pointCut()") public void around(ProceedingJoinPoint pjp) { System.out.println("AOP Aronud before..."); try { pjp.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("AOP Aronud after..."); } }
六、测试结果
原文出处:
Liant, Spring AOP用法详解, https://www.cnblogs.com/liantdev/p/10125284.html
tanwubo, spring aop注解详解, https://blog.csdn.net/qq_22606825/article/details/80760231
甜的柠檬酸, SpringBoot项目的pom依赖之@Aspect引入不了, https://blog.csdn.net/hyly_zhard/article/details/95628649
rainbow702, Spring AOP @Before @Around @After 等 advice 的执行顺序, https://blog.csdn.net/rainbow702/article/details/52185827