实战代码(四):Springboot AOP实现接口访问次数统计

补充说明:统计所有接口的总访问次数

一、理论基础

1.1 AOP是什么

  • AOP(Aspect Oriented Programming)–面向切面编程
  • 可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术

以上介绍来自百度百科-AOP

1.2 AOP能做什么

  • 统计接口访问次数
  • 增强功能:在不改动代码的情况下,为接口增加一些额外的功能

二、实战代码

2.1 依赖引入

<!-- AOP -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.4</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version>
</dependency>
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.12</version>
</dependency>

2.2 AOP示例

/*** API访问历史统计* @author yangjunqiang*/
@Component
@Aspect
public class ApiVisitHistory {private Logger log = LoggerFactory.getLogger(ApiVisitHistory.class);ThreadLocal<Long> startTime = new ThreadLocal<>();/*** 定义切面* - 此处代表com.smile.demo.controller包下的所有接口都会被统计*/@Pointcut("execution(* com.smile.demo.controller..*.*(..))")public void pointCut(){}/*** 在接口原有的方法执行前,将会首先执行此处的代码*/@Before("pointCut()")public void doBefore(JoinPoint joinPoint) throws Throwable {startTime.set(System.currentTimeMillis());//获取传入目标方法的参数Object[] args = joinPoint.getArgs();log.info("类名:{}", joinPoint.getSignature().getDeclaringType().getSimpleName());log.info("方法名:{}", joinPoint.getSignature().getName() );// 计数AtomicCounter.getInstance().increase();}/*** 只有正常返回才会执行此方法* 如果程序执行失败,则不执行此方法*/@AfterReturning(returning = "returnVal", pointcut = "pointCut()")public void doAfterReturning(JoinPoint joinPoint, Object returnVal) {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();log.info("所有接口的总访问次数:{}", AtomicCounter.getInstance().getValue());}/*** 当接口报错时执行此方法*/@AfterThrowing(pointcut = "pointCut()")public void doAfterThrowing(JoinPoint joinPoint) {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();log.info("接口访问失败,URI:[{}], 耗费时间:[{}] ms", request.getRequestURI(), System.currentTimeMillis() - startTime.get());}
}

2.3 定义接口,进行测试

@RestController
@RequestMapping("/demo/aop")
public class HelloController {@GetMapping("hello")public String hello() {return "hello World!";}@GetMapping("hello2")public String hello2() {int i = 1 / 0;return "测试报错的AOP方法";}
}

2.4 源码地址

https://github.com/lysmile/spring-boot-demo/tree/master/springboot-aop-demo