SpringBoot方法级耗时监控实现方案
·
1. 基于AOP的耗时监控
1.1 添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
1.2 自定义监控注解
java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeMonitor {
String value() default "";
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
boolean logResult() default false;
}
1.3 实现AOP切面
java
@Aspect
@Component
@Slf4j
public class ExecutionTimeAspect {
@Around("@annotation(timeMonitor)")
public Object monitorExecutionTime(ProceedingJoinPoint joinPoint,
TimeMonitor timeMonitor) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = null;
try {
result = joinPoint.proceed();
return result;
} finally {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
long convertedDuration = convertTimeUnit(duration, timeMonitor.timeUnit());
logExecutionTime(joinPoint, timeMonitor, convertedDuration, result);
}
}
private long convertTimeUnit(long duration, TimeUnit timeUnit) {
switch (timeUnit) {
case SECONDS: return duration / 1000;
case MICROSECONDS: return duration * 1000;
case NANOSECONDS: return duration * 1000000;
default: return duration;
}
}
private void logExecutionTime(ProceedingJoinPoint joinPoint, TimeMonitor timeMonitor,
long duration, Object result) {
String methodName = joinPoint.getSignature().toShortString();
String message = String.format("方法 %s 执行耗时: %d %s",
methodName, duration, getTimeUnitString(timeMonitor.timeUnit()));
if (timeMonitor.logResult() && result != null) {
message += String.format(" | 返回结果: %s", result.toString());
}
log.info(message);
}
private String getTimeUnitString(TimeUnit timeUnit) {
switch (timeUnit) {
case SECONDS: return "s";
case MILLISECONDS: return "ms";
case MICROSECONDS: return "μs";
case NANOSECONDS: return "ns";
default: return "ms";
}
}
}
1.4 使用示例
java
@Service
public class UserService {
@TimeMonitor(value = "用户查询", timeUnit = TimeUnit.MILLISECONDS, logResult = true)
public User getUserById(Long id) {
// 业务逻辑
return userRepository.findById(id).orElse(null);
}
@TimeMonitor("批量用户查询")
public List<User> getUsers(List<Long> ids) {
// 业务逻辑
return userRepository.findAllById(ids);
}
}
2. 基于Spring Boot Actuator的监控
2.1 添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
2.2 配置Metrics监控
java
@Component
public class MethodMetrics {
private final MeterRegistry meterRegistry;
private final Map<String, Timer> timers = new ConcurrentHashMap<>();
public MethodMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
public void recordExecutionTime(String methodName, long duration, TimeUnit unit) {
Timer timer = timers.computeIfAbsent(methodName,
key -> Timer.builder("method.execution.time")
.tag("method", methodName)
.register(meterRegistry));
timer.record(duration, unit);
}
@EventListener
public void handleMethodExecutionEvent(MethodExecutionEvent event) {
recordExecutionTime(event.getMethodName(),
event.getDuration(),
event.getTimeUnit());
}
}
3. 高级功能:统计和告警
3.1 监控统计类
java
@Component
@Slf4j
public class MethodPerformanceMonitor {
private final Map<String, MethodStats> statsMap = new ConcurrentHashMap<>();
private final long warningThreshold;
public MethodPerformanceMonitor(@Value("${monitor.warning-threshold:1000}") long warningThreshold) {
this.warningThreshold = warningThreshold;
}
public void recordMethodExecution(String methodName, long duration) {
MethodStats stats = statsMap.computeIfAbsent(methodName, k -> new MethodStats());
stats.recordExecution(duration);
// 超过阈值告警
if (duration > warningThreshold) {
log.warn("方法 {} 执行耗时 {}ms 超过阈值 {}ms",
methodName, duration, warningThreshold);
}
// 定期输出统计信息
if (stats.getExecutionCount() % 100 == 0) {
log.info("方法 {} 统计: {}", methodName, stats.getStatsSummary());
}
}
@Scheduled(fixedRate = 60000) // 每分钟输出一次汇总统计
public void printSummary() {
log.info("=== 方法执行耗时统计汇总 ===");
statsMap.forEach((method, stats) -> {
log.info("方法 {}: {}", method, stats.getStatsSummary());
});
}
@Data
public static class MethodStats {
private long executionCount;
private long totalTime;
private long maxTime;
private long minTime = Long.MAX_VALUE;
public void recordExecution(long duration) {
executionCount++;
totalTime += duration;
maxTime = Math.max(maxTime, duration);
minTime = Math.min(minTime, duration);
}
public double getAverageTime() {
return executionCount == 0 ? 0 : (double) totalTime / executionCount;
}
public String getStatsSummary() {
return String.format("调用次数: %d, 平均耗时: %.2fms, 最大耗时: %dms, 最小耗时: %dms",
executionCount, getAverageTime(), maxTime, minTime);
}
}
}
3.2 增强的AOP切面
java
@Aspect
@Component
@Slf4j
public class EnhancedExecutionTimeAspect {
private final MethodPerformanceMonitor performanceMonitor;
public EnhancedExecutionTimeAspect(MethodPerformanceMonitor performanceMonitor) {
this.performanceMonitor = performanceMonitor;
}
@Around("@annotation(timeMonitor)")
public Object monitorExecutionTime(ProceedingJoinPoint joinPoint,
TimeMonitor timeMonitor) throws Throwable {
String methodName = getMethodName(joinPoint);
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
return result;
} catch (Throwable throwable) {
log.error("方法 {} 执行异常", methodName, throwable);
throw throwable;
} finally {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
// 记录执行时间
performanceMonitor.recordMethodExecution(methodName, duration);
// 记录详细日志
if (log.isDebugEnabled()) {
log.debug("方法 {} 执行耗时: {}ms", methodName, duration);
}
}
}
private String getMethodName(ProceedingJoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
return signature.getDeclaringType().getSimpleName() + "." + signature.getName();
}
}
4. 配置类
java
@Configuration
@EnableAspectJAutoProxy
@EnableScheduling
public class MonitorConfig {
@Bean
@ConditionalOnMissingBean
public MethodPerformanceMonitor methodPerformanceMonitor() {
return new MethodPerformanceMonitor(1000L);
}
@Bean
public EnhancedExecutionTimeAspect enhancedExecutionTimeAspect(
MethodPerformanceMonitor performanceMonitor) {
return new EnhancedExecutionTimeAspect(performanceMonitor);
}
}
5. 应用配置
yaml
# application.yml
monitor:
warning-threshold: 500 # 告警阈值,单位ms
logging:
level:
com.yourpackage.monitor: DEBUG
management:
endpoints:
web:
exposure:
include: metrics
endpoint:
metrics:
enabled: true
使用方式
-
基本使用:在需要监控的方法上添加
@TimeMonitor注解 -
自定义配置:通过注解参数调整时间单位和是否记录返回值
-
查看统计:系统会自动输出方法执行统计信息
-
监控告警:当方法执行时间超过阈值时会输出警告日志
更多推荐



所有评论(0)