package cn.iocoder.yudao.server;
|
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.BeansException;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
import org.springframework.context.ApplicationListener;
|
import org.springframework.stereotype.Component;
|
|
import java.util.ArrayList;
|
import java.util.Comparator;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
/**
|
* 启动耗时监控:记录每个 Bean 的初始化耗时,启动完成后输出 Top 50 最慢的 Bean
|
*/
|
@Slf4j
|
@Component
|
public class StartupTimeMonitor implements BeanPostProcessor, ApplicationListener<ApplicationReadyEvent> {
|
|
private final Map<String, Long> beanStartTime = new ConcurrentHashMap<>();
|
private final Map<String, Long> beanDurations = new ConcurrentHashMap<>();
|
private final AtomicInteger beanCount = new AtomicInteger(0);
|
|
@Override
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
beanStartTime.put(beanName, System.nanoTime());
|
return bean;
|
}
|
|
@Override
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
Long start = beanStartTime.remove(beanName);
|
if (start != null) {
|
long duration = System.nanoTime() - start;
|
if (duration > 1_000_000) { // 只记录 > 1ms 的
|
beanDurations.put(beanName, duration);
|
}
|
beanCount.incrementAndGet();
|
}
|
return bean;
|
}
|
|
@Override
|
public void onApplicationEvent(ApplicationReadyEvent event) {
|
List<Map.Entry<String, Long>> sorted = new ArrayList<>(beanDurations.entrySet());
|
sorted.sort(Map.Entry.<String, Long>comparingByValue().reversed());
|
|
long totalMs = sorted.stream().mapToLong(Map.Entry::getValue).sum() / 1_000_000;
|
|
log.info("========== 启动耗时分析 ==========");
|
log.info("Bean 总数: {}, 初始化总耗时: {} 秒", beanCount.get(), totalMs / 1000.0);
|
log.info("========== Top 50 最慢 Bean ==========");
|
|
int topN = Math.min(50, sorted.size());
|
for (int i = 0; i < topN; i++) {
|
Map.Entry<String, Long> entry = sorted.get(i);
|
double ms = entry.getValue() / 1_000_000.0;
|
log.info(String.format(" %d. %s - %.1f 毫秒", i + 1, entry.getKey(), ms));
|
}
|
log.info("====================================");
|
}
|
}
|