一、需求
有时候代码中需要监控某个方法的具体执行时间,从网上找了找资料,简单整理一下
二、pom依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
<scope>compile</scope>
</dependency>
三、两种实现方式:工具类、切面
(一)、注解方式(推荐使用)
1、自定义注解
package com.example.stopwatch.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StopWatch {
String value() default "";
}
2、编写切面
package com.example.stopwatch;
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;
import org.springframework.util.StopWatch;
/**
* @version 1.0
* @description: 方法执行时间切面
* @date 2023/3/29 14:54
*/
@Slf4j
@Aspect
@Component
public class StopWatchAspect {
@Pointcut("@annotation(com.example.stopwatch.annotation.StopWatch)")
public void stopWatchPointCut() {
}
@Around("stopWatchPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
return logCostTime(point);
}
private Object logCostTime(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
stopWatch.start("class:" + className + " method:" + methodName);
//执行方法
Object result = joinPoint.proceed();
stopWatch.stop();
log.info("log-" + stopWatch.toString());
return result;
}
}
(二)、工具类方式
1、工具类代码
package com.example.stopwatch;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @Author:
* @Description
* @Date: 下午6:29 2023/4/20
*/
public class StopWatchUtil {
private final String id;
private List<StopWatchUtil.TaskInfo> taskList;
private String currentTaskName;
private long startTimeNanos;
private StopWatchUtil.TaskInfo lastTaskInfo;
private int taskCount;
private long totalTimeNanos;
public StopWatchUtil() {
this("");
}
public StopWatchUtil(String id) {
this(id, true);
}
public StopWatchUtil(String id, boolean keepTaskList) {
this.id = id;
if (keepTaskList) {
this.taskList = new ArrayList();
}
}
public String getId() {
return this.id;
}
public void setKeepTaskList(boolean keepTaskList) {
if (keepTaskList) {
if (null == this.taskList) {
this.taskList = new ArrayList();
}
} else {
this.taskList = null;
}
}
public void start() throws IllegalStateException {
this.start("");
}
public void start(String taskName) throws IllegalStateException {
if (null != this.currentTaskName) {
throw new IllegalStateException("Can't start StopWatch: it's already running");
} else {
this.currentTaskName = taskName;
this.startTimeNanos = System.nanoTime();
}
}
public void stop() throws IllegalStateException {
if (null == this.currentTaskName) {
throw new IllegalStateException("Can't stop StopWatch: it's not running");
} else {
long lastTime = System.nanoTime() - this.startTimeNanos;
this.totalTimeNanos += lastTime;
this.lastTaskInfo = new StopWatchUtil.TaskInfo(this.currentTaskName, lastTime);
if (null != this.taskList) {
this.taskList.add(this.lastTaskInfo);
}
++this.taskCount;
this.currentTaskName = null;
}
}
public boolean isRunning() {
return this.currentTaskName != null;
}
public String currentTaskName() {
return this.currentTaskName;
}
public long getLastTaskTimeNanos() throws IllegalStateException {
if (this.lastTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task interval");
} else {
return this.lastTaskInfo.getTimeNanos();
}
}
public long getLastTaskTimeMillis() throws IllegalStateException {
if (this.lastTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task interval");
} else {
return this.lastTaskInfo.getTimeMillis();
}
}
public String getLastTaskName() throws IllegalStateException {
if (this.lastTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task name");
} else {
return this.lastTaskInfo.getTaskName();
}
}
public StopWatchUtil.TaskInfo getLastTaskInfo() throws IllegalStateException {
if (this.lastTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task info");
} else {
return this.lastTaskInfo;
}
}
public long getTotalTimeNanos() {
return this.totalTimeNanos;
}
public long getTotalTimeMillis() {
return nanosToMillis(this.totalTimeNanos);
}
public double getTotalTimeSeconds() {
return nanosToSeconds(this.totalTimeNanos);
}
public int getTaskCount() {
return this.taskCount;
}
public StopWatchUtil.TaskInfo[] getTaskInfo() {
if (null == this.taskList) {
throw new UnsupportedOperationException("Task info is not being kept!");
} else {
return (StopWatchUtil.TaskInfo[]) this.taskList.toArray(new StopWatchUtil.TaskInfo[0]);
}
}
public String shortSummary() {
return stringFormat("StopWatch '{}': running time = {} ns", this.id, new Object[]{this.totalTimeNanos});
}
public String prettyPrint() {
String lineSeparator = System.lineSeparator();
StringBuilder sb = new StringBuilder(this.shortSummary());
sb.append(lineSeparator);
if (null == this.taskList) {
sb.append("No task info kept");
} else {
sb.append("---------------------------------------------").append(lineSeparator);
sb.append("ns % Task name").append(lineSeparator);
sb.append("---------------------------------------------").append(lineSeparator);
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumIntegerDigits(9);
nf.setGroupingUsed(false);
NumberFormat pf = NumberFormat.getPercentInstance();
pf.setMinimumIntegerDigits(3);
pf.setGroupingUsed(false);
StopWatchUtil.TaskInfo[] var5 = this.getTaskInfo();
int var6 = var5.length;
for (int var7 = 0; var7 < var6; ++var7) {
StopWatchUtil.TaskInfo task = var5[var7];
sb.append(nf.format(task.getTimeNanos())).append(" ");
sb.append(pf.format((double) task.getTimeNanos() / (double) this.getTotalTimeNanos())).append(" ");
sb.append(task.getTaskName()).append(lineSeparator);
}
}
return sb.toString();
}
public String toString() {
StringBuilder sb = new StringBuilder(this.shortSummary());
if (null == this.taskList) {
StopWatchUtil.TaskInfo[] var2 = this.getTaskInfo();
int var3 = var2.length;
for (int var4 = 0; var4 < var3; ++var4) {
StopWatchUtil.TaskInfo task = var2[var4];
sb.append("; [").append(task.getTaskName()).append("] took ").append(task.getTimeNanos()).append(" ns");
long percent = Math.round(100.0D * (double) task.getTimeNanos() / (double) this.getTotalTimeNanos());
sb.append(" = ").append(percent).append("%");
}
} else {
sb.append("; no task info kept");
}
return sb.toString();
}
public static long nanosToMillis(long duration) {
return TimeUnit.NANOSECONDS.toMillis(duration);
}
public static double nanosToSeconds(long duration) {
return (double) duration / 1.0E9D;
}
public static String stringFormat(String message, String delimStr, Object... argArray) {
if (message == null) {
return message;
} else if (argArray == null) {
return message;
} else {
if (delimStr == null || delimStr.length() == 0) {
delimStr = "{}";
}
int i = 0;
StringBuilder sbuf = new StringBuilder(message.length() + 50);
for (int L = 0; L < argArray.length; ++L) {
int j = message.indexOf(delimStr, i);
if (j == -1) {
if (i == 0) {
return message;
}
sbuf.append(message, i, message.length());
return sbuf.toString();
}
sbuf.append(message, i, j);
deeplyAppendParameter(sbuf, argArray[L], new HashMap());
i = j + delimStr.length();
}
sbuf.append(message, i, message.length());
return sbuf.toString();
}
}
private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) {
if (o == null) {
sbuf.append("null");
} else {
if (!o.getClass().isArray()) {
safeObjectAppend(sbuf, o);
} else if (o instanceof boolean[]) {
booleanArrayAppend(sbuf, (boolean[]) ((boolean[]) o));
} else if (o instanceof byte[]) {
byteArrayAppend(sbuf, (byte[]) ((byte[]) o));
} else if (o instanceof char[]) {
charArrayAppend(sbuf, (char[]) ((char[]) o));
} else if (o instanceof short[]) {
shortArrayAppend(sbuf, (short[]) ((short[]) o));
} else if (o instanceof int[]) {
intArrayAppend(sbuf, (int[]) ((int[]) o));
} else if (o instanceof long[]) {
longArrayAppend(sbuf, (long[]) ((long[]) o));
} else if (o instanceof float[]) {
floatArrayAppend(sbuf, (float[]) ((float[]) o));
} else if (o instanceof double[]) {
doubleArrayAppend(sbuf, (double[]) ((double[]) o));
} else {
objectArrayAppend(sbuf, (Object[]) ((Object[]) o), seenMap);
}
}
}
private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) {
sbuf.append('[');
if (!seenMap.containsKey(a)) {
seenMap.put(a, (Object) null);
int len = a.length;
for (int i = 0; i < len; ++i) {
deeplyAppendParameter(sbuf, a[i], seenMap);
if (i != len - 1) {
sbuf.append(", ");
}
}
seenMap.remove(a);
} else {
sbuf.append("...");
}
sbuf.append(']');
}
private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; ++i) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; ++i) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void charArrayAppend(StringBuilder sbuf, char[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; ++i) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void shortArrayAppend(StringBuilder sbuf, short[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; ++i) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void intArrayAppend(StringBuilder sbuf, int[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; ++i) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void longArrayAppend(StringBuilder sbuf, long[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; ++i) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void floatArrayAppend(StringBuilder sbuf, float[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; ++i) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {
sbuf.append('[');
int len = a.length;
for (int i = 0; i < len; ++i) {
sbuf.append(a[i]);
if (i != len - 1) {
sbuf.append(", ");
}
}
sbuf.append(']');
}
private static void safeObjectAppend(StringBuilder sbuf, Object o) {
try {
String oAsString = o.toString();
sbuf.append(oAsString);
} catch (Throwable var3) {
sbuf.append("[FAILED toString()]");
}
}
public static final class TaskInfo {
private final String taskName;
private final long timeNanos;
TaskInfo(String taskName, long timeNanos) {
this.taskName = taskName;
this.timeNanos = timeNanos;
}
public String getTaskName() {
return this.taskName;
}
public long getTimeNanos() {
return this.timeNanos;
}
public long getTimeMillis() {
return nanosToMillis(this.timeNanos);
}
public double getTimeSeconds() {
return nanosToSeconds(this.timeNanos);
}
}
}
四、测试类
package com.example.stopwatch;
import com.alibaba.fastjson.JSON;
import com.example.stopwatch.annotation.StopWatch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @Author:
* @Description
* @Date: 下午5:06 2023/4/20
*/
@Slf4j
@Service
public class StopWatchTest {
/**
* 注解方式
*/
@StopWatch
public void test() {
log.info("StopWatch注解开始测试");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 直接写到方法中
*/
public static void test1() {
log.info("StopWatch工具类开始测试");
try {
StopWatchUtil stopWatch = new StopWatchUtil();
stopWatch.start("测试一开始");
Thread.sleep(1000);
stopWatch.stop();
stopWatch.start("测试二开始");
Thread.sleep(3000);
stopWatch.stop();
log.info("*********所有任务总耗时:{}毫秒", stopWatch.getTotalTimeMillis());
log.info("*********耗时详情:{}", JSON.toJSONString(stopWatch.getTaskInfo()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
test1();
}
}
五、接口类测试注解方式使用
package com.example.api;
import com.example.service.ExcelService;
import com.example.stopwatch.StopWatchTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
/**
* @Author:
* @Description
* @Date: 下午2:00 2023/4/18
*/
@RestController
@RequestMapping("/excel")
public class ExcelApi {
@Autowired
private ExcelService excelService;
@Autowired
private StopWatchTest stopWatchTest;
@GetMapping("test1")
public String test1() {
stopWatchTest.test();
return "成功";
}
/**
* 直接输出到前端
*
* @param response
*/
@GetMapping("/export/one")
public void downloadOne(HttpServletResponse response) {
excelService.exportExcelByDtoClientNew(response);
}
/**
* 先将文件写到本地,然后读取文件,返回给前端,最后删除本地文件
*
* @param response
*/
@GetMapping("/export")
public void download(HttpServletResponse response) {
excelService.exportExcelByDtoClient(response);
}
}