性能优化之为优化接口做铺垫

 背景

作为一名有良心的开发选手,既然要做产品,咱们就要把产品做好,让用户有更好的用户体验,好的用户体验体现在哪里呢?

1.精简的业务逻辑

2.表现层(视觉,界面,导航设计):良好的页面展示

3.强力的后台处理能力

4.最大程度解决用户的问题

5.有求必应的运维体系

今天就从第三点“强力的后台处理能力”入手,强力的后台处理能力体现在哪里?无非就是,前端请求后台接口的处理速度,这时候有些老铁可能想起来,F12里面的接口耗时,但是这只是一部分接口的时间,我们怎样来统计整个项目的接口耗时呢?你可能想到:

1.在请求入口做dao操作

2.Aop

今天就用这两种方式来统计整个项目的接口耗时!

在请求入口做dao操作

这个方案我相信大多数开发人员都能想到,话不多说,开干!

我们项目使用的是vert.x框架,有别于现在市面上特别流行的springMVC,但是原理都差不多,只要找到请求的入口就事半功倍了,vert.x框架把前端传过来的接口类,方法,参数,通过反射调用目标方法,我们只要在反射的前后统计一下调用方法的耗时即可!

ExecutorService service= Executors.newFixedThreadPool(3);

long start = System.currentTimeMillis();
//反射调用的方法  这里省略掉了
long costTime = System.currentTimeMillis() - start;

//httpMethod:接口请求方式:post GET
//ip:客户端ip
//url:请求的接口类
//classMethod:请求的接口方法
//params:请求的接口的参数
//costTime:请求的接口耗时
if(costTime >1000){
//异步统计接口耗时信息
service.execute(()->this.insertCostTimeRecord(httpMethod,ip,url,classMethod,params,costTime));
}

其中我是用了使用线程池异步做dao操作,减少统计耗时操作对原有逻辑性能上的影响。costTime >1000,只统计耗时大于1秒的接口,我们的目的是优化,二八原则,你懂得!

接下来,看结果吧,如图:

 跟我预先想的一致呀,以后只用看这张表的统计信息就知道是哪个接口慢了,不会再让你为了优化无从下手!

AOP

AOP(Aspect Oriented Programming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。

Aop的好处:

  • 集中处理某一关注点 / 横切逻辑

  • 可以很方便的添加 / 删除关注点

  • 侵入性少,增强代码可读性及可维护性 因此当想打印请求日志时很容易想到切面,对控制层代码 0 侵入 

切面的使用【基于注解】

  • @Aspect => 声明该类为一个注解类

切点注解:

  • @Pointcut => 定义一个切点,可以简化代码

通知注解:

  • @Before => 在切点之前执行代码

  • @After => 在切点之后执行代码

  • @AfterReturning => 切点返回内容后执行代码,可以对切点的返回值进行封装

  • @AfterThrowing => 切点抛出异常后执行

  • @Around => 环绕,在切点前后执行代码

动手写一个请求日志切面

  • 使用 @Pointcut 定义切点

@Pointcut("execution(* your_package.controller..*(..))")  
public void requestServer() {  
}  

 @Pointcut 定义了一个切点,因为是请求日志切边,因此切点定义的是 Controller 包下的所有类下的方法。定义切点以后在通知注解中直接使用 requestServer 方法名就可以了

  • 完整切面代码

@Component  
@Aspect  
public class RequestLogAspect {  
 private final static Logger LOGGER = LoggerFactory.getLogger(RequestLogAspect.class);  
  
 ExecutorService service= Executors.newFixedThreadPool(3);
 @Pointcut("execution(* your_package.controller..*(..))")  
 public void requestServer() {  
 }  
  
@Around("requestServer()")  
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {  
 long start = System.currentTimeMillis();  
 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();  
 HttpServletRequest request = attributes.getRequest();  
 Object result = proceedingJoinPoint.proceed();  
 RequestInfo requestInfo = new RequestInfo();  
 requestInfo.setIp(request.getRemoteAddr());  
 requestInfo.setUrl(request.getRequestURL().toString());  
 requestInfo.setHttpMethod(request.getMethod());  
 requestInfo.setClassMethod(String.format("%s.%s", proceedingJoinPoint.getSignature().getDeclaringTypeName(),  
 proceedingJoinPoint.getSignature().getName()));  
 requestInfo.setRequestParams(getRequestParamsByProceedingJoinPoint(proceedingJoinPoint));  
 requestInfo.setResult(result);  
 requestInfo.setTimeCost(System.currentTimeMillis() - start);  
 LOGGER.info("Request Info      : {}", JSON.toJSONString(requestInfo));  
      //异步统计接口耗时信息
    service.execute(()->this.insertCostTimeRecord(requestInfo));
 return result;  
}  
  
 /**  
  * 获取入参  
  * @param proceedingJoinPoint  
  *  
  * @return  
  * */  
 private Map<String, Object> getRequestParams(ProceedingJoinPoint proceedingJoinPoint) {  
 Map<String, Object> requestParams = new HashMap<>();  
  
 //参数名  
 String[] paramNames =  
((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();  
 //参数值  
 Object[] paramValues = proceedingJoinPoint.getArgs();  
  
 for (int i = 0; i < paramNames.length; i++) {  
 Object value = paramValues[i];  
  
 //如果是文件对象  
 if (value instanceof MultipartFile) {  
 MultipartFile file = (MultipartFile) value;  
 value = file.getOriginalFilename();  //获取文件名  
 }  
  
 requestParams.put(paramNames[i], value);  
 }  
  
 return requestParams;  
 }  
}  
 

就此,使用Aop统计接口耗时开发完成,结果与第一种方式的结果一致。

有了这个功能,你还会为了不知道优化哪个接口而头疼吗?来吧,老铁,给你的项目加上吧!

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值