AOP面向切面编程
1 什么是AOP?
AOP
是面向切面编程,是Spring Framework
的核心子模块;- 是一种设计思想,在不修改源代码的情况下给程序统一添加额外功能的一种技术。
2 AOP的作用?
- 代码重用:将一些通用的功能(比如日志记录、安全控制等)抽象出来,形成可重用的模块;
- 简化开发:使开发人员将关注点从业务逻辑中分离出来,使得开发更加简单明了;
- 提高系统可扩展性:在系统需求变化时,只需要修改AOP模块而不是修改业务逻辑,这可以使得系统更加易于扩展和维护;
- 降低代码耦合度:将不同的关注点分离开来,这可以避免代码之间的紧耦合。
3 使用AOP的流程?
-
第1步:添加依赖,刷新
Maven
;-
<!--引入aop依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
-
第2步:创建切面类,添加
@Aspect
注解;-
@Aspect @Component public class LogAspect { /** * Before注解: 前置通知,在目标方法执行之前执行; * value参数: 切入点表达式,指定哪些方法需要被植入增强逻辑; */ @Before(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))") public void beforeMethod(){ //前置通知的增强逻辑 } }
-
-
第3步:编写切入点表达式,使用各种通知注解对目标函数进行功能增强。
4 什么是切入点表达式?
在 AOP 中,切入点表达式指定了哪些方法需要被植入增强逻辑。它是一个表达式,用于 匹配目标对象中的方法,并提供切入点的精确定义,比如:
execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))
5 五种通知类型
1、**前置通知:**目标方法执行前执行 @Before
2、**返回通知:**目标方法成功结束后执行 @AfterReturning
3、**异常通知:**目标方法出现异常时执行 @AfterThrowing
4、**环绕通知:**环绕通知是环绕一个目标方法,环绕通知需要携带ProceedingJoinPoint类型的参数,该参数可以决定是否执行目标方法,环绕通知必须有返回值,返回值必须和目标方法的返回值一致 @Around
5、**后置通知:**目标方法执行后执行 @After
返回通知和后置通知区别:
1、执行时机
前置通知和返回通知的区别:前置通知在目标方法执行前执行,返回通知在目标方法执行后执行
2、权限不同
返回通知可以拿到目标方法的返回值(returning 参数),
后置通知无法拿到目标方法的返回值
示例:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* Aspect注解
* 1、表示当前类是一个切面类
* 2、可以定义切面方法,为目标方法进行功能增强;
*
* 通知类型
* 1、前置通知:目标方法执行前执行 @Before
* 2、返回通知:目标方法成功结束后执行 @AfterReturning
* 3、异常通知:目标方法出现异常时执行 @AfterThrowing
* 4、环绕通知:环绕通知,环绕通知是环绕一个目标方法,环绕通知需要携带ProceedingJoinPoint类型的参数,
* 该参数可以决定是否执行目标方法,环绕通知必须有返回值,返回值必须和目标方法的返回值一致 @Around
* 5、后置通知:目标方法执行后执行 @After
*
* 返回通知和后置通知区别:
* 执行时机
* 前置通知和返回通知的区别:前置通知在目标方法执行前执行,返回通知在目标方法执行后执行
* 权限不同
* 返回通知可以拿到目标方法的返回值(returning 参数),
* 后置通知无法拿到目标方法的返回值
*/
@Aspect
@Component
public class LogAspect {
// 开始日志的方法
/* 1、前置通知
@Before(value = "") 前置通知 表示在目标方法执行前执行该方法
比如调用add方法之前执行beforeMethod方法
value参数 :切入点表达式 确定哪些方法需要被植入增强逻辑
切入点表达式:
value = "execution(* cn.practice._07springaop.aop.CalculatorImpl.*(..))"
固定格式:execution(方法修饰符 返回值 方法所在包名.类名.方法名(参数列表))"
JoinPoint:连接点,即被增强的方法 拦截到的的方法
1、JoinPoint可以获取方法名,方法参数,方法所在包名,方法所在类名
*/
// @Before(value = "execution(public int cn.practice._07springaop.aop.CalculatorImpl.*(..))")
// public void beforeMethod(JoinPoint joinPoint){
// // 从方法中获取方法名
// String methodName = joinPoint.getSignature().getName();
// // 从方法中获取参数
Object[] args = joinPoint.getArgs();
// String args = Arrays.toString(joinPoint.getArgs());
//
// System.out.println("[前置通知]"+ methodName + "方法开始,参数为:" + args);
// }
/*
2、返回通知:目标方法 成功结束后执行
@AfterReturning(value = "execution(* cn.practice._07springaop.aop.CalculatorImpl.*(..))",returning = "result")
returning:获取目标方法的返回值
*/
// @AfterReturning(value = "execution(public int cn.practice._07springaop.aop.CalculatorImpl.*(..))",returning = "result")
// public void afterReturningMethod(JoinPoint joinPoint,Object result){
// // 从方法中获取方法名
// String methodName = joinPoint.getSignature().getName();
//
// System.out.println("[返回通知]"+ methodName + "方法结束,结果为:" + result);
// }
/*
3、后置通知:目标方法成功结束和异常都会执行一般用于释放资源
*/
// @After(value = "execution(public int cn.practice._07springaop.aop.CalculatorImpl.*(..))")
// public void afterMethod(JoinPoint joinPoint){
// // 从方法中获取方法名
// String methodName = joinPoint.getSignature().getName();
//
// System.out.println("[后置通知]"+ methodName + "方法彻底执行结束");
// }
/*
4、异常通知
@AfterThrowing(value = "execution(* cn.practice._07springaop.aop.CalculatorImpl.*(..))",throwing = "ex")
*/
// @AfterThrowing(value = "execution(public int cn.practice._07springaop.aop" +
// ".CalculatorImpl.*(..))",throwing = "ex")
// public void afterThrowingMethod(JoinPoint joinPoint,Throwable ex){
// // 从方法中获取方法名
// String methodName = joinPoint.getSignature().getName();
//
// System.out.println("[异常通知]"+ methodName + "方法出现异常:" + ex.getMessage());
// }
/**
* 5.环绕通知[Around注解]:
* 1.目标方法执行前后都执行
* 2.目标方法抛出异常时也会执行
* 3.可以获取到目标方法得返回值
* 4.可以获取到一擦汗给你对象
* 环绕通知 == 前置通知+返回通知+异常通知+后置通知
*
*
* ProceedingJoinPoint是JoinPoint的子类:连接点,即被增强的方法
*/
@Around(value = "execution(public int cn.practice._07springaop.aop.CalculatorImpl.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint){
// 异常捕获
Object result = null;
try{
// 获取目标方法
// 前置通知
System.out.println("111 - 前置通知");
// 执行目标方法 具体执行的方法的返回值
result = joinPoint.proceed();
// 如果没有抛出异常 返回通知
System.out.println("333 - 返回通知");
}catch (Throwable e){
// 抛出异常 异常通知
System.out.println("222 - 异常通知");
throw new RuntimeException(e);
}finally {
// 后置通知
System.out.println("444 - 后置通知");
}
return result;
}
}