利用AOP监控Java接口响应超时

 

为什么要监控

  服务化接口是提供服务的,接口正确性、稳定性是最最重要的,在保证正确的同时需要尽量提高接口响应时间。

  有的团队会有专门的工具来对系统响应时间、吞吐量做监控,但如果团队没有这种“待遇”就需要自己来做一些工具为自己的代码提供服务。

自己动手,丰衣足食

  AOP + Annotation 简陋实现,能达到目的

  AOP : 使用环绕方式对接口拦截,在拦截接口前后记录时间最后计算用时

  Annotation : 自定义注解在接口上设置超时时间(timeout)和超时是否发送邮件选项(emailIfTimeout)

  通过对接口实际执行时间和配置的超时时间比较,系统可以计算出接口是否超时,此时可使用日志(或其他能通知到开发人员的方式)记录具体哪个接口、什么参数以及执行时间

  注解可以提供更多的选项,来为自己接口服务,比如支持注解到类上,批量为接口设置了默认超时时间、支持日志中显示的处理方法名称 等等...

代码实施

接口Annotation定义

package opsteel.oupuzw.web.logistics.bean;

import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 创建自定义注解输出接口耗时(@PrintCostTime)
 * create on 2018-08-08
 * @author Yesh
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrintCostTime {

    /** 输出方法名称 **/
    @AliasFor("name")
    String name() default "";

    /**
     * 接口超时时间,单位毫秒.默认值100毫秒
     * @return 设置的超时时间
     */
    int timeout() default 100;

    /**
     * 注解上的打印参数
     * @return 输出的时候打印出来
     */
    String[] printArgs() default {};

    /**
     * 是否开启日志监控功能默认开
     * @return 返回ture需要发送邮件
     */
    boolean enablePrint() default true;

    /**
     * 是否允许打印在默认列表里的参数(默认 true)
     * @return
     */
    boolean enablePrintDefaultArgs() default true;

    /**
     * 当接口响应超时时,是否发送邮件.默认发送
     * @return 返回ture需要发送邮件
     */
    boolean emailIfTimeout() default true;
}
package opsteel.oupuzw.web.logistics.bean;

import lombok.extern.log4j.Log4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 日志AOP监控接口响应时长
 * create on 2018-08-08
 *
 * @author Yesh
 */
@Component
@Aspect
@Log4j
public class PrintCostTimeAspect {

    @Around("@annotation(opsteel.oupuzw.web.logistics.bean.PrintCostTime)")
    public Object aroundPrintCostTime(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature(); //方法签名
        PrintCostTime printCostTime = signature.getMethod().getAnnotation(PrintCostTime.class);//从签名注解中获取注解内容配置项
        String methodCName = printCostTime.name();//方法中文名称[注解中获取 不填写 为""]
        String methodName = signature.getName();
        //        Class clazz = pjp.getTarget().getClass();  //取拦截的Class
        //RequestMapping requestMapping = signature.getMethod().getAnnotation(RequestMapping.class);//从这里可以获取 请求地址
        //方法名和参数值
        //String[] ArgsNames = signature.getParameterNames();
        //Object[] argsValue = pjp.getArgs();
        //参数打印目前没必要 result 中可以获取 返回的json值
//        String argsLog = getArgsLog(printCostTime, ArgsNames, argsValue);

        long start = System.currentTimeMillis();  //开始时间
        Object[] args = pjp.getArgs(); //取拦截的Args
        Object result = pjp.proceed(args);  //运行被拦截的方法
        if (printCostTime.enablePrint()==false){ //若开关为 true 开启打印
            return result;
        }

        long end = System.currentTimeMillis();
        long diff = end - start;//计算耗时

        //若超过配置的阀值则打印耗时日志
        long thresholdInMs = printCostTime.timeout();
        if (diff >= thresholdInMs) {
            log.info(methodCName + ":[" + methodName + "]" + ",响应时间: " + diff + " ms");
            //发邮件发作即可
        }
        return result;
    }

}

 

@PrintCostTime(name = "XXX")

在Controller注解上即可描述当前接口花费时间

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值