|
|
|
@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
package com.ruoyi.framework.aspectj;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.ruoyi.common.annotation.PerformanceMonitor;
|
|
|
|
|
|
|
|
import org.aspectj.lang.ProceedingJoinPoint;
|
|
|
|
|
|
|
|
import org.aspectj.lang.annotation.Around;
|
|
|
|
|
|
|
|
import org.aspectj.lang.annotation.Aspect;
|
|
|
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
|
|
|
|
import java.util.concurrent.atomic.LongAdder;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 性能监控切面
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @author ruoyi
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Aspect
|
|
|
|
|
|
|
|
@Component
|
|
|
|
|
|
|
|
public class PerformanceAspect {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(PerformanceAspect.class);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 性能统计信息
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static final Map<String, PerformanceStats> statsMap = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 环绕通知:记录接口执行时间
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
@Around("@annotation(performanceMonitor)")
|
|
|
|
|
|
|
|
public Object around(ProceedingJoinPoint joinPoint, PerformanceMonitor performanceMonitor) throws Throwable {
|
|
|
|
|
|
|
|
String methodName = joinPoint.getSignature().toShortString();
|
|
|
|
|
|
|
|
long startTime = System.currentTimeMillis();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 记录开始时间
|
|
|
|
|
|
|
|
PerformanceStats stats = statsMap.computeIfAbsent(methodName, k -> new PerformanceStats());
|
|
|
|
|
|
|
|
stats.totalCalls.increment();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
// 执行方法
|
|
|
|
|
|
|
|
Object result = joinPoint.proceed();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算执行时间
|
|
|
|
|
|
|
|
long executionTime = System.currentTimeMillis() - startTime;
|
|
|
|
|
|
|
|
stats.totalTime.add(executionTime);
|
|
|
|
|
|
|
|
stats.minTime.updateAndGet(min -> min == 0 ? executionTime : Math.min(min, executionTime));
|
|
|
|
|
|
|
|
stats.maxTime.updateAndGet(max -> Math.max(max, executionTime));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 慢查询日志
|
|
|
|
|
|
|
|
if (executionTime > performanceMonitor.slowThreshold()) {
|
|
|
|
|
|
|
|
log.warn("⚠️ 慢查询警告: {} 执行时间: {}ms (阈值: {}ms)",
|
|
|
|
|
|
|
|
methodName, executionTime, performanceMonitor.slowThreshold());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (performanceMonitor.logParams()) {
|
|
|
|
|
|
|
|
log.debug("参数: {}", joinPoint.getArgs());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
|
|
|
stats.errorCalls.increment();
|
|
|
|
|
|
|
|
log.error("❌ 接口异常: {} 执行时间: {}ms, 异常: {}",
|
|
|
|
|
|
|
|
methodName, System.currentTimeMillis() - startTime, e.getMessage());
|
|
|
|
|
|
|
|
throw e;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取性能统计信息
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static Map<String, PerformanceStats> getPerformanceStats() {
|
|
|
|
|
|
|
|
return new HashMap<>(statsMap);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 清空性能统计
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static void clearStats() {
|
|
|
|
|
|
|
|
statsMap.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 性能统计信息
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static class PerformanceStats {
|
|
|
|
|
|
|
|
public final LongAdder totalCalls = new LongAdder();
|
|
|
|
|
|
|
|
public final LongAdder totalTime = new LongAdder();
|
|
|
|
|
|
|
|
public final AtomicLong minTime = new AtomicLong(0);
|
|
|
|
|
|
|
|
public final AtomicLong maxTime = new AtomicLong(0);
|
|
|
|
|
|
|
|
public final LongAdder errorCalls = new LongAdder();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取平均响应时间
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public long getAvgTime() {
|
|
|
|
|
|
|
|
long calls = totalCalls.sum();
|
|
|
|
|
|
|
|
return calls == 0 ? 0 : totalTime.sum() / calls;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取成功率
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public double getSuccessRate() {
|
|
|
|
|
|
|
|
long calls = totalCalls.sum();
|
|
|
|
|
|
|
|
if (calls == 0) return 100.0;
|
|
|
|
|
|
|
|
long errors = errorCalls.sum();
|
|
|
|
|
|
|
|
return ((calls - errors) * 100.0) / calls;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|