前言:
基于SpringBoot项目。切面编程为了实现代码的复用性。和一些公共功能的处理。如日志管理、接口耗时打印、接口鉴权等。此时使用切面编程最佳不过。
业务场景:本系统需要调用一些外部开源API(如阿里云、百度AI开放平台等),对接接口较多切比较耗时。所以写一个记录接口耗时的查看实际应用到业务场景后会不会超过工程默认接口超时时间,以便后面进行调整。
一、代码实现
1、依赖导入(Maven)
除了SpringBoot基本的依赖之外(spring-boot-starter-web)外还需要导入AOP依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、编写@interface接口
//注解作用范围(类上、方法上、属性上) 此为方法上
@Target(ElementType.METHOD)
//运行环境
@Retention(RetentionPolicy.RUNTIME)
public @interface TakeUpTime {
//接口编写时输入,接口中文名
String value() default "";
}
3、编写切面实现类
package org.java.demo.springbootdemo.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
//声明这是切面AOP类,后面的程序时将此类代理
@Aspect
//注入到spring容器
@Component
//日志打印工具
@Slf4j
public class TakeUpTimeAspect {
//切入点 类似监听范围 controller包下的所有类、方法 监听的注解是 刚编写的@InterFace 路径
@Pointcut("execution(public * org.java.demo.springbootdemo.controller.*.*(..))&&@annotation(org.java.demo.springbootdemo.aspect.TakeUpTime)")
public void timeInterface(){}
//类型:环绕通知 切入点
@Around("timeInterface()")
public Object roundAdvice(ProceedingJoinPoint point) throws Throwable {
//声明Object 准备接收返回值
Object result = null;
long startTime = System.currentTimeMillis();
//获取入参,有时对入参过滤可以使用。
Object[] args = point.getArgs();
//别切入方法所有信息
MethodSignature signature = (MethodSignature) point.getSignature();
//获取该方法注解上的属性参数
TakeUpTime annotation = signature.getMethod().getAnnotation(TakeUpTime.class);
String value = annotation.value();
//执行添加注解的方法
result = point.proceed();
Long time = System.currentTimeMillis() - startTime;
//获取方法名称
String methodName = signature.getName();
log.info("方法名称:{}",methodName);
log.info("{}-API的{}方法耗时{}毫秒",value,methodName,time);
log.info("耗时:{}毫秒",time.toString());
return result;
}
}
注意的是类上的注解不要忘记。@slf4j 看实际业务是否需要
4、编写接口controller实现
@RestController
@RequestMapping("/aop")
public class AopController {
@GetMapping("/baidu")
@TakeUpTime("百度")
public String baiduApi() throws InterruptedException {
//模拟接口耗时
Thread.sleep(1000);
return "SUCCESS~";
}
@GetMapping("/alibaba")
@TakeUpTime("阿里")
public String alibaba() throws InterruptedException {
//模拟接口耗时
Thread.sleep(800);
return "SUCCESS~";
}
}
/*调用localhost:8080/aop/baidu
打印如下:
方法名称:baiduApi
百度-API的baiduApi方法耗时1022毫秒
耗时:1022毫秒 */
/*调用localhost:8080/aop/alibaba
打印如下:
方法名称:alibaba
阿里-API的alibaba方法耗时807毫秒
耗时:807毫秒 */
总结:
好了,这就时注解+aop实现了最简单的注解形式的切面操作了。后面的高端用法还需要探索。