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 { private final Map beanStartTime = new ConcurrentHashMap<>(); private final Map 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> sorted = new ArrayList<>(beanDurations.entrySet()); sorted.sort(Map.Entry.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 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("===================================="); } }