前言
何为AOP?AOP就是面向切面的编程。
何为面向切面的编程?就像高速公路的省界收费站一样,每条进出我们省的高速都会在省界上设立一个收费站,那么省界就是一个切面,收费站就是我们的处理方案,我们需要做的是定义省界这个面和在面上的收费站的功能。
应用场景
在项目完成之后,交付之前我们一般会对程序进行压力测试,在测试中怎么更加精准的定位系统运行的瓶颈呢?这时候你需要AOP监测每个接口甚至每个方法执行的时间!
在项目做异常处理时,我们怎样才能更加简单明了,将所有异常统一截取到同一个方法中进行处理?这时候你需要AOP将抛出的异常接受并处理!
AOP的定义非常灵活,可以是返回值类型,也可以是注释,也可以是某一个包下的所有方法或者指定方法,所以学习AOP之后,你不需要担心没有用武之地!
AOP结构
首先需要在这个类上添加一个@Aspect注释,这就声明了这个类是一个切面。
如下例子,将所有返回值为指定类型的方法定义为一个切面:
@Aspect @Component @Slf4j public class ResultAspect { // 切入点 所有返回值类型是com.test.xbo包下ResultBO的方法 @Pointcut("execution(public com.test.xbo.ResultBO *(..))") public void ResultAspect() { } // 环绕通知,参数必须为ProceedingJoinPoint,proceed就是被切面的方法 @Around("ResultAspect()") public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); joinPoint.proceed(); String str = "## 控制器运行时间:" + joinPoint.getSignature() + ":" + (System.currentTimeMillis() - startTime); return null; } }
再如,我定义一个注释,将所有添加该注释的方法定义为一个切面:
1、定义一个注释,添加该注释的方法会打印出该方法执行的时间:
@Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface DoneTime { String param() default ""; }
2、定义一个切面
@Aspect @Component @Slf4j public class DoneTimeAspect { @Around("@annotation(doneTime)") public Object around(ProceedingJoinPoint joinPoint, DoneTime doneTime) throws Throwable { long startTime = System.currentTimeMillis(); Object o = joinPoint.proceed(); String str = "## DoneTime-" + joinPoint.getSignature() + ":" + (System.currentTimeMillis() - startTime); log.error(str); return o; } }
这样我们就完成了两个非常典型的AOP切面的例子!