什么是AOP
在Spring Boot AOP中,非核心业务功能被定义为切面,核心和非核心功能都开发完成之后,再将两者编织在一起,这就是AOP。
举个例子,假设你的应用程序需要记录每次方法调用的开始时间和结束时间。如果你不使用AOP,你可能需要在每个方法的开头和结尾都写一段代码来记录时间。但是,这样的做法既繁琐又容易遗漏。
使用AOP,你可以创建一个"时间记录"的切面,告诉系统在每个方法执行前后都执行一段代码来记录时间。这样,你就可以把时间记录这个关注点从业务逻辑中剥离出来,让每个方法专注于自己的核心任务,而不必担心时间记录。
AOP中的编程术语和常用注解
切面:非核心业务功能就被定义为切面。比如一个系统的日志功能,它贯穿整个核心业务的逻辑,因此叫做切面
切入点:在哪些类的哪些方法上面切入
通知:在方法执行前/后或者执行前后做什么
前置通知:在被代理方法之前执行
后置通知:在被代理方法之后执行
返回通知:被代理方法正常返回之后执行
异常通知:被代理方法抛出异常时执行
环绕通知:是AOP中强大、灵活的通知,集成前置和后置通知
springboot常见的使用注解
@Pointcut 定义切点
@Before 前置通知
@After 后置通知
@AfterReturning 返回通知
@AfterThrowing 异常通知
@Around 环绕通知
切点常用写法
1)execution(public * (..))——表示匹配所有public方法
2)execution( set(..))——表示所有以“set”开头的方法
3)execution( com.example.controller.TestController.(..))——表示匹配所有TestController接口的方法
4)execution( com.example.controler..(..))——表示匹配controler包下所有的方法
5)execution(* com.example.service...(..))——表示匹配controler包和它的子包下的方法
JoinPoint 对象
JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
方法名 功能
Signature getSignature(); 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs(); 获取传入目标方法的参数对象
Object getTarget(); 获取被代理的对象
Object getThis(); 获取代理对象
ProceedingJoinPoint对象
ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中,
Object proceed() throws Throwable //执行目标方法
Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法
使用aop,第一步导入maven dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
编写Controller类
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("hello")
public String sayHello(){
System.out.println("hello");
return "hello";
}
}
定义切面
@Aspect
@Component
public class TestAspect {
@Pointcut("execution(* com.example.demo.controller.TestController.sayHello())")
private void serviceMethods() {}
// 前置通知,在目标方法执行前执行
@Before("serviceMethods()")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("Before executing: " + joinPoint.getSignature().toShortString());
}
// 后置通知,在目标方法执行后执行
@After("serviceMethods()")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("After executing: " + joinPoint.getSignature().toShortString());
}
// 返回通知,在目标方法成功返回后执行
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
System.out.println("After returning from: " + joinPoint.getSignature().toShortString());
System.out.println("Result: " + result);
}
// 异常通知,在目标方法抛出异常时执行
@AfterThrowing(pointcut = "serviceMethods()", throwing = "exception")
public void afterThrowingAdvice(JoinPoint joinPoint, Exception exception) {
System.out.println("Exception thrown from: " + joinPoint.getSignature().toShortString());
System.out.println("Exception: " + exception.getMessage());
}
// 环绕通知,在目标方法执行前后都可以插入逻辑
@Around("serviceMethods()")
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Around - Before executing: " + proceedingJoinPoint.getSignature().toShortString());
// 执行目标方法
Object result = proceedingJoinPoint.proceed();
System.out.println("Around - After executing: " + proceedingJoinPoint.getSignature().toShortString());
return result;
}
}
切面类需要打上@Aspect注解表示这是一个切面类,并且加上@Component注解
首先是定义切点,只需定义一个方法,在上面使用@Pointcut注解即可,注解里面内容含义如下:
execution 代表方法被执行时触发
* 代表任意返回值的方法
com.example.demo.controller.TestController.sayHello(..)被织入类的全限定名
(..) 表示任意的参数
发起一个请求
通过这个,我们也可以发现各个通知的执行顺序,由于这个案例使用@Around的时候,先执行了一步,之后在执行其他的通知
Around -> Before -> AfterReturning -> After -> Around
总结
AOP其实使用起来是个很方便的东西,大大降低了相关功能之间的耦合度,使得整个系统井井有条。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。