在spring中,很多功能和特性的实现都是基于aop切面来实现的,比如事务功能、异步处理、代理等。在spring框架中也已经给我们提供了面向切面编程的功能,通过几个注解就可以完成。
要使用spring提供的aop功能,首先需要引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在编写一个实现类,在这个类中添加aop相关的注解实现web接口请求到响应的耗时:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.example.pojo.ApiResult;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.stereotype.Component;
/**
* 应用切面类
*
* @author xingo
* @date 2023/12/12
*/
@Aspect
@Component
@ConditionalOnWebApplication
public class AopAspect {
// 通过环绕通知方式处理
/**
* 定义切入点
*/
@Pointcut("execution(* org.example.controller.*.*(..))")
public void pointcut() {
}
/**
* 环绕通知
* @param pj
* @return
*/
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint pj) throws Throwable {
long start = System.currentTimeMillis();
// 执行目标方法
Object result = pj.proceed();
if(result == null) {
return result;
}
long diff = System.currentTimeMillis() - start;
if(result instanceof ApiResult) {
ApiResult temp = (ApiResult) result;
temp.setTime(diff);
}
System.out.println("请求耗时 ====>>> " + diff);
return result;
}
// 通过前置通知和后置通知方式处理
// /**
// * 请求开始时间
// */
// public static final ThreadLocal<Long> threadStartTime = new ThreadLocal<>();
//
// /**
// * 前置通知:执行目标方法之前运行
// * @param jp
// */
// @Before("execution(* org.example.controller.*.*(..))")
// public void beforeMethod(JoinPoint jp) {
// threadStartTime.set(System.currentTimeMillis());
// }
//
// /**
// * 返回通知:目标方法正常返回值后运行
// * @param jp
// */
// @AfterReturning(value = "execution(* org.example.controller.*.*(..))", returning = "result")
// public void aftherReturn(JoinPoint jp, Object result) {
// long diff = System.currentTimeMillis() - threadStartTime.get();
// threadStartTime.remove();
// System.out.println("请求耗时 ====>>> " + diff);
// if(result instanceof ApiResult) {
// ApiResult temp = (ApiResult) result;
// temp.setTime(diff);
// }
// }
//
// /**
// * 异常通知:目标方法出现异常后运行
// * @param jp
// */
// @AfterThrowing(value = "execution(* org.example.controller.*.*(..))", throwing = "e")
// public void afterThrowing(JoinPoint jp, Exception e) {
// e.printStackTrace();
// long diff = System.currentTimeMillis() - threadStartTime.get();
// threadStartTime.remove();
// System.out.println("请求耗时 ====>>> " + diff);
// }
// /**
// * 后置通知:目标方法运行结束之后,不管有没有异常
// * @param jp
// */
// @After("execution(* org.example.controller.*.*(..))")
// public void afterMethod(JoinPoint jp) {
// long diff = System.currentTimeMillis() - threadStartTime.get();
// threadStartTime.remove();
// System.out.println("请求耗时 ====>>> " + diff);
// }
}
上面是对 org.example.controller 包下以及所有子包下的类和方法进行拦截,统计方法调用耗时。该功能可以有两种方式实现:一种是使用环绕通知实现;另一种是通过前置通知和后置通知方式实现。
spring中通过aop可以实现很多功能,可以在某些方法执行前后做一些加强操作,记录方法处理日志,做权限拦截等等。总之可以通过使用aop避免写一些重复代码,让开发者更关注业务逻辑开发。