package com.ecep.contract; import java.time.Duration; import java.util.Locale; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.boot.ConfigurableBootstrapContext; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplicationHook; import org.springframework.boot.SpringApplicationRunListener; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; import org.springframework.boot.context.metrics.buffering.StartupTimeline; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.EventListener; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.metrics.StartupStep; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.data.web.config.EnableSpringDataWebSupport.PageSerializationMode; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import com.ecep.contract.cloud.CloudRepositoriesConfig; import com.ecep.contract.ds.DsRepositoriesConfig; import com.ecep.contract.util.TaskMonitorCenter; @SpringBootApplication(exclude = { org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration.class, RedisReactiveAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class }) @EnableScheduling @EnableAsync @EnableCaching @EnableSpringDataWebSupport(pageSerializationMode = PageSerializationMode.VIA_DTO) public class SpringApp { private final TaskMonitorCenter taskMonitorCenter; private static final Logger logger = LoggerFactory.getLogger(SpringApp.class); static SpringApplication application; static ConfigurableApplicationContext context; SpringApp(TaskMonitorCenter taskMonitorCenter) { this.taskMonitorCenter = taskMonitorCenter; } public static T getBean(Class requiredType) throws BeansException { return context.getBean(requiredType); } public static void launch(Properties properties, MessageHolder holder) { // holder.debug("应用程序环境准备中..."); SpringApplication.withHook(new Hook(holder), () -> { // 动态地注册或修改这些组件和配置 application.addBootstrapRegistryInitializer(registry -> { // System.out.println("registry = " + registry); }); application.addListeners(event -> { logger.debug("SpringApp.launch ApplicationListener, event:{}", event); }); application.addInitializers(app -> { logger.debug("SpringApp.launch ApplicationContextInitializer"); ConfigurableEnvironment environment = app.getEnvironment(); logger.debug("environment = {}", environment); PropertySource dynamicProperties = environment.getPropertySources().get("dynamicProperties"); if (dynamicProperties != null) { logger.debug("dynamicProperties = {}", dynamicProperties); } environment.getPropertySources().addLast(new PropertiesPropertySource("dynamicProperties", properties)); // app.getBeanFactory().registerSingleton("dataSource", dataSource()); logger.debug("app = {}", app); if (app instanceof AnnotationConfigApplicationContext ctx) { ctx.register(DsRepositoriesConfig.class); ctx.register(CloudRepositoriesConfig.class); } }); // startup.start(""); context = application.run(); logger.debug("SpringApp.launch application.run()."); // Duration between = Duration.between(startup.getBufferedTimeline().getStartTime(), Instant.now()); // holder.info("应用程序环境加载完成... " + between); }); // CompletableFuture.runAsync(() -> { // // 在这里调用 startup 性能分析 // analyzeStartupPerformance(startup); // }, Desktop.instance.getExecutorService()); } /** * 分析启动性能数据并输出到日志 */ private static void analyzeStartupPerformance(BufferingApplicationStartup startup) { // 获取所有记录的事件 StartupTimeline timeline = startup.getBufferedTimeline(); if (timeline == null || timeline.getEvents().isEmpty()) { logger.warn("StartupTimeline 为空或没有事件!"); return; } logger.info("总共有 {} 个事件", timeline.getEvents().size()); // 找出与 Bean 初始化相关的步骤 timeline.getEvents().stream() .filter(event -> event.getStartupStep().getName().startsWith("spring.beans.")) .sorted((a, b) -> Long.compare(b.getDuration().toMillis(), a.getDuration().toMillis())) .limit(30) .forEach(event -> { String name = event.getStartupStep().getName(); long duration = event.getDuration().toMillis(); logger.info("Bean 初始化阶段: {} - 耗时: {} ms", name, duration); for (StartupStep.Tag tag : event.getStartupStep().getTags()) { if ("beanName".equals(tag.getKey())) { logger.info(" └── Bean 名称: {}", tag.getValue()); } } }); } public static String getMessage(String code, Object[] args, Locale locale) { return context.getMessage(code, args, locale); } public static void shutdown() { System.out.println("SpringApp.shutdown"); if (logger.isDebugEnabled()) { logger.debug("shutdown"); } if (context != null) { if (context.isRunning()) { context.close(); } } } public static boolean isRunning() { return context != null && context.isRunning(); } static class Hook implements SpringApplicationHook, SpringApplicationRunListener { MessageHolder holder; Hook(MessageHolder holder) { this.holder = holder; } public void debug(String msg) { holder.debug(msg); } @Override public void starting(ConfigurableBootstrapContext bootstrapContext) { logger.debug("Desktop.starting"); debug("Spring Application 启动中..."); } @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { logger.debug("Desktop.environmentPrepared"); debug("初始化 Environment 中,请稍后..."); } @Override public void contextPrepared(ConfigurableApplicationContext context) { logger.debug("Desktop.contextPrepared"); debug("Spring Application Context 预处理中,请稍后..."); } @Override public void contextLoaded(ConfigurableApplicationContext context) { logger.debug("Desktop.contextLoaded"); debug("Spring Application Context 初始化完毕,请稍后..."); } @Override public void started(ConfigurableApplicationContext context, Duration timeTaken) { logger.debug("Desktop.started"); debug("Spring Application 启动完毕."); } @Override public void ready(ConfigurableApplicationContext context, Duration timeTaken) { logger.debug("Desktop.ready"); debug("Spring Application ready."); } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { logger.error("Desktop.failed", exception); holder.error("Spring Application 启动失败(" + exception.getMessage() + ")."); } @Override public SpringApplicationRunListener getRunListener(SpringApplication springApplication) { return this; } } @EventListener public void handleClosedEvent(ContextClosedEvent event) { if (logger.isDebugEnabled()) { logger.debug("handleClosedEvent={}", event); } } public static TaskMonitorCenter getTaskMonitorCenter() { return getBean(TaskMonitorCenter.class); } // @Bean // public ScheduledExecutorService scheduledExecutorService() { // return Desktop.instance.getExecutorService(); // } }