Spring-Boot+AOP+统计单次请求方法的执行次数和耗时情况

package com.yanshu.aspect;


import java.util.*;




import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.ProceedingJoinPoint;  
import org.aspectj.lang.annotation.AfterReturning;  
import org.aspectj.lang.annotation.Around;  
import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
import org.aspectj.lang.annotation.Pointcut;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.stereotype.Component;  
  


/**
 * 拦截器
 * @author Administrator
 *
 */
//@Aspect
//@Component
public class ControllerInterceptor {
//定义一个日志的全局的静态
private static Logger logger =LoggerFactory.getLogger(ControllerInterceptor.class);

//ThreadLocal 维护变量 避免同步   
    //ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。  
    ThreadLocal<Long> startTime = new ThreadLocal<>();// 开始时间  
   //ThreadLocal 维护变量 避免同步 ThreadLocal是一个关于创建线程局部变量的类、
    //通常情况下,我们创建的变量是可以被任何一个线程访问并且修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程无法访问和修改。
    //ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独以地改变自己的副本,而不会影响其它线程所对应的副本
    ThreadLocal<Long> startTimes=new ThreadLocal<>();//开始时间
      
    /** 
     * map1存放方法被调用的次数O 
     */  
    ThreadLocal<Map<String, Long >> map1 = new ThreadLocal<>();  
    
     /** 
     * map2存放方法总耗时 
     */  
    ThreadLocal<Map<String, Long >> map2 = new ThreadLocal<>();  
      
      
    /** 
     * 定义一个切入点. 解释下: 
     * 
     * ~ 第一个 * 代表任意修饰符及任意返回值. ~ 第二个 * 定义在web包或者子包 ~ 第三个 * 任意方法 ~ .. 匹配任意数量的参数. 
     */  
   /// static final String pCutStr = "execution(* com.appleyk.*..*(..))";  
   // static final String pCutStr = "execution(* com.yanshu.controller..*..*(..))";  
    static final String pCutStr = "execution(* com.yanshu.*..*(..))";  
    @Pointcut(value = pCutStr)  
    public void logPointcut() {  
    }  
  
    /**
     * Aop:环绕通知 切整个包下面的所有涉及到调用的方法的信息
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("logPointcut()")  
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {  
  
          
        //初始化 一次  
        if(map1.get() ==null ){  
            map1.set(new HashMap<>());  
              
        }  
          
        if(map2.get() == null){  
            map2.set(new HashMap<>());  
        }  
          
        long start = System.currentTimeMillis();  
        try {  
            Object result = joinPoint.proceed();  
            if(result==null){  
                //如果切到了 没有返回类型的void方法,这里直接返回  
                return null;  
            }  
            long end = System.currentTimeMillis();  
  
            logger.info("===================");  
            String tragetClassName = joinPoint.getSignature().getDeclaringTypeName();  
            String MethodName = joinPoint.getSignature().getName();  
                                      
            Object[] args = joinPoint.getArgs();// 参数  
            int argsSize = args.length;  
            String argsTypes = "";  
            String typeStr = joinPoint.getSignature().getDeclaringType().toString().split(" ")[0];  
            String returnType = joinPoint.getSignature().toString().split(" ")[0];  
            logger.info("类/接口:" + tragetClassName + "(" + typeStr + ")");  
            logger.info("方法:" + MethodName);  
            logger.info("参数个数:" + argsSize);  
            logger.info("返回类型:" + returnType);  
            if (argsSize > 0) {  
                // 拿到参数的类型  
                for (Object object : args) {  
                    argsTypes += object.getClass().getTypeName().toString() + " ";  
                }  
                logger.info("参数类型:" + argsTypes);  
            }  
  
            Long total = end - start;  
            logger.info("耗时: " + total + " ms!");  
                      
            if(map1.get().containsKey(MethodName)){  
                Long count = map1.get().get(MethodName);  
                map1.get().remove(MethodName);//先移除,在增加  
                map1.get().put(MethodName, count+1);  
                  
                count = map2.get().get(MethodName);  
                map2.get().remove(MethodName);  
                map2.get().put(MethodName, count+total);  
            }else{  
                  
                map1.get().put(MethodName, 1L);  
                map2.get().put(MethodName, total);  
            }  
              
            return result;  
  
        } catch (Throwable e) {  
            long end = System.currentTimeMillis();  
            logger.info("====around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : "  
                    + e.getMessage());  
            throw e;  
        }  
  
    }  
  
    //对Controller下面的方法执行前进行切入,初始化开始时间  
    @Before(value = "execution(* com.yanshu.controller.*.*(..))")  
    public void beforMehhod(JoinPoint jp) {  
        startTime.set(System.currentTimeMillis());  
    }  
  
    //对Controller下面的方法执行后进行切入,统计方法执行的次数和耗时情况  
    //注意,这里的执行方法统计的数据不止包含Controller下面的方法,也包括环绕切入的所有方法的统计信息  
    @AfterReturning(value = "execution(* com.yanshu.controller.*.*(..))")  
    public void afterMehhod(JoinPoint jp) {  
        long end = System.currentTimeMillis();  
        long total =  end - startTime.get();  
        String methodName = jp.getSignature().getName();  
        logger.info("连接点方法为:" + methodName + ",执行总耗时为:" +total+"ms");  
          
        //重新new一个map  
        Map<String, Long> map = new HashMap<>();  
          
        //从map2中将最后的 连接点方法给移除了,替换成最终的,避免连接点方法多次进行叠加计算     
        //由于map2受ThreadLocal的保护,这里不支持remove,因此,需要单开一个map进行数据交接  
        for(Map.Entry<String, Long> entry:map2.get().entrySet()){  
            if(entry.getKey().equals(methodName)){                
                map.put(methodName, total);  
                  
            }else{  
                map.put(entry.getKey(), entry.getValue());  
            }             
        }  
      
        for (Map.Entry<String, Long> entry :map1.get().entrySet()) {  
            for(Map.Entry<String, Long> entry2 :map.entrySet()){  
                if(entry.getKey().equals(entry2.getKey())){  
                    System.err.println(entry.getKey()+",被调用次数:"+entry.getValue()+",综合耗时:"+entry2.getValue()+"ms");  
                }  
            }  
              
        }  
    }  





}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值