Spring Boot 启动流程源码解析

作者:湮酒日期:2025/10/28

⚙️Spring Boot 启动流程源码解析

文章目录

  • ⚙️Spring Boot 启动流程源码解析
  • 🎯 一、Spring Boot 启动流程概览
    • 🔄 启动流程全景图
    • ⏱️ 启动阶段时间线
  • 🏗️ 二、SpringApplication 初始化阶段
    • 🚀 SpringApplication.run() 入口分析
    • 🔧 应用类型推断机制
    • 📦 工厂加载机制
  • ⚙️ 三、启动前准备:Banner、Environment、Listener
    • 🚀 run() 方法执行流程
    • 🎨 Banner 打印机制
    • 🌍 Environment 准备过程
  • 🔄 四、创建 ApplicationContext 与加载 BeanDefinition
    • 🏗️ 应用上下文创建机制
    • 📋 上下文准备阶段
    • 🔧 上下文初始器应用
  • ⚡ 五、refresh 阶段与自动装配结合点
    • 🔄 refreshContext() 核心流程
    • 🎯 Spring Boot 特有的刷新扩展
    • 🔧 自动装配与刷新的集成点
  • 📢 六、应用启动事件与回调机制
    • 🎯 Spring Boot 启动事件体系
    • 👂 事件监听器机制
    • 🔄 运行监听器获取机制
  • 💻 七、自定义监听器与启动钩子实践
    • 🛠️ 自定义启动监听器
    • 🔧 启动性能监控工具
    • 🎯 自定义应用运行器
    • 🔧 启动故障诊断工具
  • 💎 八、总结:从 main() 到容器就绪的生命线
    • 🎯 Spring Boot 启动流程核心总结
    • 🔄 启动流程完整时序图
    • 🚀 性能优化建议
    • 🔧 调试与监控最佳实践

🎯 一、Spring Boot 启动流程概览

🔄 启动流程全景图

​​Spring Boot 应用启动时序图​​:

main() SpringApplication ApplicationContext BeanFactory EventListener run() 初始化SpringApplication 加载应用上下文初始器 加载应用事件监听器 阶段1: 启动前准备 打印Banner 准备Environment 发布ApplicationStartingEvent 阶段2: 创建应用上下文 创建ApplicationContext实例 准备应用上下文 发布ApplicationContextInitializedEvent 阶段3: 刷新上下文 refresh() 加载Bean定义 实例化单例Bean 发布ContextRefreshedEvent 阶段4: 启动完成 发布ApplicationReadyEvent 返回ApplicationContext main() SpringApplication ApplicationContext BeanFactory EventListener

⏱️ 启动阶段时间线

​​关键启动节点时间分布​​:

在这里插入图片描述

🏗️ 二、SpringApplication 初始化阶段

🚀 SpringApplication.run() 入口分析

​​启动方法核心逻辑​​:

1public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
2    return run(new Class<?>[]{primarySource}, args);
3}
4
5public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
6    // 创建SpringApplication实例并执行run方法
7    return new SpringApplication(primarySources).run(args);
8}
9

​​SpringApplication 构造函数源码​​:

1public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
2    this.resourceLoader = resourceLoader;
3    
4    // 1. 设置主配置类(不能为null)
5    Assert.notNull(primarySources, "PrimarySources must not be null");
6    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
7    
8    // 2. 推断应用类型(Servlet、Reactive、None)
9    this.webApplicationType = WebApplicationType.deduceFromClasspath();
10    
11    // 3. 加载应用上下文初始器(从spring.factories)
12    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
13    
14    // 4. 加载应用事件监听器(从spring.factories)
15    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
16    
17    // 5. 推断主应用类(从堆栈跟踪)
18    this.mainApplicationClass = deduceMainApplicationClass();
19}
20

🔧 应用类型推断机制

​​WebApplicationType.deduceFromClasspath() 源码​​:

1static WebApplicationType deduceFromClasspath() {
2    // 检查类路径是否存在特定的类来判断应用类型
3    
4    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) 
5        && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) 
6        && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
7        return WebApplicationType.REACTIVE;  // WebFlux应用
8    }
9    
10    for (String className : SERVLET_INDICATOR_CLASSES) {
11        if (!ClassUtils.isPresent(className, null)) {
12            return WebApplicationType.NONE;  // 非Web应用
13        }
14    }
15    
16    return WebApplicationType.SERVLET;  // Servlet Web应用
17}
18

​​应用类型推断的类路径检查​​:

1// 关键类路径检查常量
2private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
3private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
4private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
5private static final String[] SERVLET_INDICATOR_CLASSES = { 
6    "javax.servlet.Servlet", 
7    "org.springframework.web.context.ConfigurableWebApplicationContext" 
8};
9

📦 工厂加载机制

​​getSpringFactoriesInstances() 方法实现​​:

1private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
2    return getSpringFactoriesInstances(type, new Class<?>[]{});
3}
4
5private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
6    ClassLoader classLoader = getClassLoader();
7    
8    // 1. 使用SpringFactoriesLoader加载实现类名称
9    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
10    
11    // 2. 创建实例
12    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
13    
14    // 3. 排序(支持@Order注解)
15    AnnotationAwareOrderComparator.sort(instances);
16    return instances;
17}
18

⚙️ 三、启动前准备:Banner、Environment、Listener

🚀 run() 方法执行流程

​​SpringApplication.run() 完整实现​​:

1public ConfigurableApplicationContext run(String... args) {
2    // 1. 创建启动计时器
3    StopWatch stopWatch = new StopWatch();
4    stopWatch.start();
5    
6    // 2. 初始化上下文和异常报告器
7    ConfigurableApplicationContext context = null;
8    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
9    
10    // 3. 设置Headless模式
11    configureHeadlessProperty();
12    
13    try {
14        // 4. 获取运行监听器并发布启动事件
15        SpringApplicationRunListeners listeners = getRunListeners(args);
16        listeners.starting();
17        
18        try {
19            // 5. 准备环境
20            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
21            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
22            
23            // 6. 打印Banner
24            Banner printedBanner = printBanner(environment);
25            
26            // 7. 创建应用上下文
27            context = createApplicationContext();
28            
29            // 8. 准备异常报告器
30            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
31                    new Class[] { ConfigurableApplicationContext.class }, context);
32            
33            // 9. 准备应用上下文
34            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
35            
36            // 10. 刷新上下文(核心阶段)
37            refreshContext(context);
38            
39            // 11. 刷新后处理(空实现,子类可扩展)
40            afterRefresh(context, applicationArguments);
41            
42            // 12. 停止计时器
43            stopWatch.stop();
44            
45            // 13. 发布启动完成事件
46            if (this.logStartupInfo) {
47                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
48            }
49            listeners.started(context);
50            
51            // 14. 执行Runner回调
52            callRunners(context, applicationArguments);
53            
54        } catch (Throwable ex) {
55            // 异常处理
56            handleRunFailure(context, ex, exceptionReporters, listeners);
57            throw new IllegalStateException(ex);
58        }
59        
60        // 15. 发布应用就绪事件
61        listeners.ready(context);
62        return context;
63        
64    } catch (Throwable ex) {
65        handleRunFailure(context, ex, exceptionReporters, null);
66        throw new IllegalStateException(ex);
67    }
68}
69

🎨 Banner 打印机制

​​Banner 打印实现细节​​:

1private Banner printBanner(ConfigurableEnvironment environment) {
2    // 1. 检查是否禁用Banner
3    if (this.bannerMode == Banner.Mode.OFF) {
4        return null;
5    }
6    
7    // 2. 获取Banner资源
8    ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
9            : new DefaultResourceLoader(getClassLoader());
10    
11    // 3. 使用BannerPrinter打印
12    SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
13    
14    // 4. 根据模式选择输出流
15    if (this.bannerMode == Mode.LOG) {
16        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
17    }
18    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
19}
20

​​自定义 Banner 实现示例​​:

1@Component
2public class CustomBanner implements Banner {
3    
4    private static final String[] BANNER = {
5        "  ___  ___         _     _      ",
6        "  |  \\/  |        | |   | |     ",
7        "  | .  . | ___  __| |___| |__   ",
8        "  | |\\/| |/ _ \\/ _` / __| '_ \\ ",
9        "  | |  | |  __/ (_| \\__ \\ | | |",
10        "  \\_|  |_/\\___|\\__,_|___/_| |_|",
11        "                                "
12    };
13    
14    @Override
15    public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
16        for (String line : BANNER) {
17            printStream.println(line);
18        }
19        
20        String version = getVersion();
21        printStream.println(" :: Spring Boot :: " + version);
22        printStream.println();
23    }
24    
25    private String getVersion() {
26        try {
27            return SpringBootVersion.getVersion();
28        } catch (Exception ex) {
29            return "v2.7.0";
30        }
31    }
32}
33

🌍 Environment 准备过程

​​prepareEnvironment() 方法详解​​:

1private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
2        ApplicationArguments applicationArguments) {
3    
4    // 1. 创建或获取Environment
5    ConfigurableEnvironment environment = getOrCreateEnvironment();
6    
7    // 2. 配置Environment(处理命令行参数等)
8    configureEnvironment(environment, applicationArguments.getSourceArgs());
9    
10    // 3. 发布Environment准备事件
11    listeners.environmentPrepared(environment);
12    
13    // 4. 绑定Environment到SpringApplication
14    bindToSpringApplication(environment);
15    
16    // 5. 检查是否自定义Environment
17    if (!this.isCustomEnvironment) {
18        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
19                deduceEnvironmentClass());
20    }
21    
22    // 6. 配置PropertySources
23    ConfigurationPropertySources.attach(environment);
24    return environment;
25}
26

​​Environment 创建逻辑​​:

1private ConfigurableEnvironment getOrCreateEnvironment() {
2    // 根据应用类型创建相应的Environment
3    if (this.environment != null) {
4        return this.environment;
5    }
6    
7    switch (this.webApplicationType) {
8    case SERVLET:
9        return new StandardServletEnvironment();
10    case REACTIVE:
11        return new StandardReactiveWebEnvironment();
12    default:
13        return new StandardEnvironment();
14    }
15}
16

🔄 四、创建 ApplicationContext 与加载 BeanDefinition

🏗️ 应用上下文创建机制

​​createApplicationContext() 方法实现​​:

1protected ConfigurableApplicationContext createApplicationContext() {
2    // 1. 根据应用类型推断上下文类
3    Class<?> contextClass = this.applicationContextClass;
4    if (contextClass == null) {
5        try {
6            switch (this.webApplicationType) {
7            case SERVLET:
8                contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
9                break;
10            case REACTIVE:
11                contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
12                break;
13            default:
14                contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
15            }
16        } catch (ClassNotFoundException ex) {
17            throw new IllegalStateException("Unable create a default ApplicationContext, " +
18                    "please specify an ApplicationContextClass", ex);
19        }
20    }
21    
22    // 2. 使用反射创建实例
23    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
24}
25

​​默认上下文类配置​​:

1// 默认上下文类常量
2public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext";
3public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext";
4public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext";
5

📋 上下文准备阶段

​​prepareContext() 方法深度解析​​:

1private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
2        SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
3    
4    // 1. 设置环境
5    context.setEnvironment(environment);
6    
7    // 2. 后处理上下文(设置资源加载器、转换服务等)
8    postProcessApplicationContext(context);
9    
10    // 3. 应用上下文初始器
11    applyInitializers(context);
12    
13    // 4. 发布上下文准备事件
14    listeners.contextPrepared(context);
15    
16    // 5. 打印启动信息
17    if (this.logStartupInfo) {
18        logStartupInfo(context.getParent() == null);
19        logStartupProfileInfo(context);
20    }
21    
22    // 6. 注册特定的单例Bean
23    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
24    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
25    if (printedBanner != null) {
26        beanFactory.registerSingleton("springBootBanner", printedBanner);
27    }
28    
29    // 7. 设置允许Bean定义覆盖
30    if (this.allowBeanDefinitionOverriding != null) {
31        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
32    }
33    
34    // 8. 添加Bean后处理器(懒加载等)
35    if (this.lazyInitialization) {
36        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
37    }
38    
39    // 9. 加载源(主配置类)
40    Set<Object> sources = getAllSources();
41    Assert.notEmpty(sources, "Sources must not be empty");
42    load(context, sources.toArray(new Object[0]));
43    
44    // 10. 发布上下文加载事件
45    listeners.contextLoaded(context);
46}
47

🔧 上下文初始器应用

​​applyInitializers() 方法实现​​:

1protected void applyInitializers(ConfigurableApplicationContext context) {
2    // 1. 遍历所有ApplicationContextInitializer
3    for (ApplicationContextInitializer initializer : getInitializers()) {
4        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
5                ApplicationContextInitializer.class);
6        
7        // 2. 检查类型匹配
8        if (requiredType != null && !requiredType.isInstance(context)) {
9            throw new IllegalStateException("Initializer " + initializer.getClass().getName() +
10                    " requires context of type " + requiredType.getName() + ", but got " + context.getClass().getName());
11        }
12        
13        // 3. 应用初始器
14        initializer.initialize(context);
15    }
16}
17

​​典型的 ApplicationContextInitializer 示例​​:

1// Spring Boot 内置的初始器示例
2public class MyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
3    
4    @Override
5    public void initialize(ConfigurableApplicationContext applicationContext) {
6        // 1. 设置配置文件位置
7        ConfigurableEnvironment environment = applicationContext.getEnvironment();
8        environment.addActiveProfile("dev");
9        
10        // 2. 添加自定义属性源
11        MapPropertySource customPropertySource = new MapPropertySource("custom", 
12            Collections.singletonMap("app.custom.property", "value"));
13        environment.getPropertySources().addFirst(customPropertySource);
14        
15        // 3. 注册自定义Bean
16        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getBeanFactory();
17        registry.registerBeanDefinition("customBean", 
18            BeanDefinitionBuilder.genericBeanDefinition(CustomBean.class).getBeanDefinition());
19    }
20}
21

⚡ 五、refresh 阶段与自动装配结合点

🔄 refreshContext() 核心流程

​​刷新上下文的关键调用​​:

1private void refreshContext(ConfigurableApplicationContext context) {
2    // 1. 注册关闭钩子
3    if (this.registerShutdownHook) {
4        try {
5            context.registerShutdownHook();
6        } catch (AccessControlException ex) {
7            // 在安全管理器环境中可能不允许
8        }
9    }
10    
11    // 2. 执行刷新(委托给AbstractApplicationContext)
12    refresh(context);
13}
14
15protected void refresh(ApplicationContext applicationContext) {
16    // 委托给ApplicationContext的refresh方法
17    if (applicationContext instanceof AbstractApplicationContext) {
18        ((AbstractApplicationContext) applicationContext).refresh();
19    }
20}
21

🎯 Spring Boot 特有的刷新扩展

​​SpringApplicationRefreshListener 的作用​​:

1// Spring Boot 对标准refresh的扩展
2@Component
3public class SpringBootRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
4    
5    private static final Logger logger = LoggerFactory.getLogger(SpringBootRefreshListener.class);
6    
7    @Override
8    public void onApplicationEvent(ContextRefreshedEvent event) {
9        ApplicationContext context = event.getApplicationContext();
10        
11        // 1. 记录刷新完成
12        logger.info("Application context refreshed: {}", context.getDisplayName());
13        
14        // 2. 执行启动后检查
15        performPostRefreshChecks(context);
16        
17        // 3. 发布自定义事件
18        context.publishEvent(new ApplicationRefreshedEvent(context));
19    }
20    
21    private void performPostRefreshChecks(ApplicationContext context) {
22        // 检查关键Bean是否就绪
23        checkRequiredBeans(context);
24        
25        // 验证配置属性
26        validateConfigurationProperties(context);
27    }
28}
29

🔧 自动装配与刷新的集成点

​​自动配置在刷新阶段的触发时机​​:

1// 在refresh()方法中的关键调用点
2@Override
3public void refresh() throws BeansException, IllegalStateException {
4    synchronized (this.startupShutdownMonitor) {
5        // ... 标准refresh流程
6        
7        // 关键点:调用BeanFactory后处理器(包括自动配置)
8        invokeBeanFactoryPostProcessors(beanFactory);
9        
10        // ... 其他步骤
11    }
12}
13

​​自动配置的触发流程​​:

ApplicationContext BeanFactoryPostProcessor AutoConfigurationImportSelector SpringFactoriesLoader invokeBeanFactoryPostProcessors() selectImports() loadFactoryNames() 加载spring.factories 返回自动配置类列表 返回需要导入的配置类 注册自动配置Bean定义 ApplicationContext BeanFactoryPostProcessor AutoConfigurationImportSelector SpringFactoriesLoader

📢 六、应用启动事件与回调机制

🎯 Spring Boot 启动事件体系

​​完整的启动事件序列​​:

1public class SpringBootEventSequence {
2    
3    /**
4     * 完整的启动事件发布顺序
5     */
6    public void demonstrateEventSequence() {
7        // 1. ApplicationStartingEvent - 启动最开始
8        // 2. ApplicationEnvironmentPreparedEvent - 环境准备完成
9        // 3. ApplicationContextInitializedEvent - 上下文初始化
10        // 4. ApplicationPreparedEvent - 上下文准备完成
11        // 5. ContextRefreshedEvent - 上下文刷新完成(Spring标准事件)
12        // 6. ApplicationStartedEvent - 应用启动完成
13        // 7. ApplicationReadyEvent - 应用准备就绪(可以接收请求)
14        // 8. AvailabilityChangeEvent - 应用状态变更
15    }
16}
17

👂 事件监听器机制

​​SpringApplicationRunListeners 的实现​​:

1class SpringApplicationRunListeners {
2    
3    private final Log log;
4    private final List<SpringApplicationRunListener> listeners;
5    
6    // 启动事件发布方法
7    void starting() {
8        for (SpringApplicationRunListener listener : listeners) {
9            listener.starting();
10        }
11    }
12    
13    void environmentPrepared(ConfigurableEnvironment environment) {
14        for (SpringApplicationRunListener listener : listeners) {
15            listener.environmentPrepared(environment);
16        }
17    }
18    
19    void contextPrepared(ConfigurableApplicationContext context) {
20        for (SpringApplicationRunListener listener : listeners) {
21            listener.contextPrepared(context);
22        }
23    }
24    
25    void contextLoaded(ConfigurableApplicationContext context) {
26        for (SpringApplicationRunListener listener : listeners) {
27            listener.contextLoaded(context);
28        }
29    }
30    
31    void started(ConfigurableApplicationContext context) {
32        for (SpringApplicationRunListener listener : listeners) {
33            listener.started(context);
34        }
35    }
36    
37    void ready(ConfigurableApplicationContext context) {
38        for (SpringApplicationRunListener listener : listeners) {
39            listener.ready(context);
40        }
41    }
42}
43

🔄 运行监听器获取机制

​​getRunListeners() 方法实现​​:

1private SpringApplicationRunListeners getRunListeners(String[] args) {
2    Class<?>[] parameterTypes = new Class<?>[] { SpringApplication.class, String[].class };
3    
4    // 1. 从spring.factories加载SpringApplicationRunListener实现
5    List<SpringApplicationRunListener> listeners = getSpringFactoriesInstances(
6            SpringApplicationRunListener.class, parameterTypes, this, args);
7    
8    // 2. 创建运行监听器包装器
9    return new SpringApplicationRunListeners(logger, listeners);
10}
11

​​典型的 SpringApplicationRunListener​​:

1public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
2    
3    private final SpringApplication application;
4    private final String[] args;
5    private final SimpleApplicationEventMulticaster initialMulticaster;
6    
7    public EventPublishingRunListener(SpringApplication application, String[] args) {
8        this.application = application;
9        this.args = args;
10        this.initialMulticaster = new SimpleApplicationEventMulticaster();
11        
12        // 注册应用监听器
13        for (ApplicationListener<?> listener : application.getListeners()) {
14            this.initialMulticaster.addApplicationListener(listener);
15        }
16    }
17    
18    @Override
19    public void starting() {
20        // 发布ApplicationStartingEvent
21        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
22    }
23    
24    @Override
25    public void environmentPrepared(ConfigurableEnvironment environment) {
26        // 发布ApplicationEnvironmentPreparedEvent
27        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
28                this.application, this.args, environment));
29    }
30    
31    // 其他事件发布方法...
32}
33

💻 七、自定义监听器与启动钩子实践

🛠️ 自定义启动监听器

​​完整的启动事件监听器示例​​:

1@Component
2@Slf4j
3public class ComprehensiveStartupListener implements 
4    ApplicationListener<ApplicationEvent>, Ordered {
5    
6    private long startupStartTime;
7    private Map<String, Long> phaseTimestamps = new LinkedHashMap<>();
8    
9    @PostConstruct
10    public void init() {
11        this.startupStartTime = System.currentTimeMillis();
12        log.info("🚀 应用启动监听器已初始化");
13    }
14    
15    @Override
16    public void onApplicationEvent(ApplicationEvent event) {
17        recordPhaseTimestamp(event.getClass().getSimpleName());
18        
19        // 处理各种启动事件
20        if (event instanceof ApplicationStartingEvent) {
21            handleStartingEvent((ApplicationStartingEvent) event);
22        } else if (event instanceof ApplicationEnvironmentPreparedEvent) {
23            handleEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
24        } else if (event instanceof ApplicationContextInitializedEvent) {
25            handleContextInitializedEvent((ApplicationContextInitializedEvent) event);
26        } else if (event instanceof ApplicationPreparedEvent) {
27            handlePreparedEvent((ApplicationPreparedEvent) event);
28        } else if (event instanceof ContextRefreshedEvent) {
29            handleContextRefreshedEvent((ContextRefreshedEvent) event);
30        } else if (event instanceof ApplicationStartedEvent) {
31            handleStartedEvent((ApplicationStartedEvent) event);
32        } else if (event instanceof ApplicationReadyEvent) {
33            handleReadyEvent((ApplicationReadyEvent) event);
34        }
35    }
36    
37    private void handleStartingEvent(ApplicationStartingEvent event) {
38        log.info("📋 1. 应用启动开始");
39        logApplicationInfo(event.getSpringApplication());
40    }
41    
42    private void handleEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
43        log.info("🌍 2. 环境准备完成");
44        logEnvironmentInfo(event.getEnvironment());
45    }
46    
47    private void handleContextInitializedEvent(ApplicationContextInitializedEvent event) {
48        log.info("🏗️ 3. 应用上下文初始化完成");
49    }
50    
51    private void handlePreparedEvent(ApplicationPreparedEvent event) {
52        log.info("📦 4. 应用准备完成,Bean定义已加载");
53        logBeanDefinitionCount(event.getApplicationContext());
54    }
55    
56    private void handleContextRefreshedEvent(ContextRefreshedEvent event) {
57        log.info("🔄 5. 应用上下文刷新完成");
58        logBeanStatistics(event.getApplicationContext());
59    }
60    
61    private void handleStartedEvent(ApplicationStartedEvent event) {
62        log.info("✅ 6. 应用启动完成");
63    }
64    
65    private void handleReadyEvent(ApplicationReadyEvent event) {
66        log.info("🎯 7. 应用准备就绪,可以处理请求");
67        generateStartupReport();
68    }
69    
70    private void recordPhaseTimestamp(String phaseName) {
71        phaseTimestamps.put(phaseName, System.currentTimeMillis() - startupStartTime);
72    }
73    
74    private void generateStartupReport() {
75        log.info("=== Spring Boot 启动性能报告 ===");
76        phaseTimestamps.forEach((phase, timestamp) -> {
77            log.info("   {}: {}ms", phase, timestamp);
78        });
79        
80        long totalTime = System.currentTimeMillis() - startupStartTime;
81        log.info("   总启动时间: {}ms", totalTime);
82        log.info("=== 报告生成完成 ===");
83    }
84    
85    @Override
86    public int getOrder() {
87        return Ordered.HIGHEST_PRECEDENCE; // 最高优先级,最先执行
88    }
89}
90

🔧 启动性能监控工具

​​启动时间分析工具类​​:

1@Component
2@Slf4j
3public class StartupPerformanceMonitor {
4    
5    private final Map<String, BeanInitInfo> beanInitInfo = new ConcurrentHashMap<>();
6    private long contextRefreshStartTime;
7    
8    @EventListener
9    public void onContextRefreshed(ContextRefreshedEvent event) {
10        this.contextRefreshStartTime = System.currentTimeMillis();
11        log.info("开始监控Bean初始化性能...");
12    }
13    
14    @EventListener 
15    public void onApplicationReady(ApplicationReadyEvent event) {
16        long totalTime = System.currentTimeMillis() - contextRefreshStartTime;
17        generatePerformanceReport(totalTime);
18    }
19    
20    @Bean
21    public static BeanPostProcessor startupMonitorBeanPostProcessor() {
22        return new BeanPostProcessor() {
23            @Override
24            public Object postProcessBeforeInitialization(Object bean, String beanName) {
25                // 记录Bean初始化开始时间
26                BeanInitInfo info = new BeanInitInfo();
27                info.setStartTime(System.currentTimeMillis());
28                info.setBeanName(beanName);
29                info.setBeanType(bean.getClass().getName());
30                return bean;
31            }
32            
33            @Override
34            public Object postProcessAfterInitialization(Object bean, String beanName) {
35                // 记录Bean初始化完成时间
36                BeanInitInfo info = getBeanInitInfo(beanName);
37                if (info != null) {
38                    info.setEndTime(System.currentTimeMillis());
39                    info.setDuration(info.getEndTime() - info.getStartTime());
40                    
41                    // 记录慢速Bean
42                    if (info.getDuration() > 100) { // 超过100ms
43                        log.warn("🐌 慢速Bean初始化: {} ({}ms)", beanName, info.getDuration());
44                    }
45                }
46                return bean;
47            }
48        };
49    }
50    
51    private void generatePerformanceReport(long totalTime) {
52        log.info("=== Bean初始化性能报告 ===");
53        
54        // 按初始化时间排序
55        beanInitInfo.values().stream()
56            .sorted(Comparator.comparingLong(BeanInitInfo::getDuration).reversed())
57            .limit(10) // 显示最慢的10个Bean
58            .forEach(info -> {
59                String speed = info.getDuration() > 100 ? "🐌" : "⚡";
60                log.info("   {} {}: {}ms", speed, info.getBeanName(), info.getDuration());
61            });
62        
63        log.info("Bean初始化总时间: {}ms", totalTime);
64        log.info("监控的Bean数量: {}", beanInitInfo.size());
65    }
66    
67    @Data
68    private static class BeanInitInfo {
69        private String beanName;
70        private String beanType;
71        private long startTime;
72        private long endTime;
73        private long duration;
74    }
75}
76

🎯 自定义应用运行器

​​CommandLineRunner 和 ApplicationRunner 示例​​:

1@Component
2@Slf4j
3public class StartupRunner implements CommandLineRunner, ApplicationRunner, Ordered {
4    
5    private final ApplicationContext context;
6    
7    public StartupRunner(ApplicationContext context) {
8        this.context = context;
9    }
10    
11    @Override
12    public void run(ApplicationArguments args) throws Exception {
13        log.info("🔧 ApplicationRunner执行开始");
14        performApplicationStartupTasks();
15    }
16    
17    @Override
18    public void run(String... args) throws Exception {
19        log.info("🔧 CommandLineRunner执行开始");
20        performCommandLineTasks(args);
21    }
22    
23    private void performApplicationStartupTasks() {
24        // 1. 检查关键Bean是否就绪
25        checkCriticalBeans();
26        
27        // 2. 验证配置属性
28        validateConfiguration();
29        
30        // 3. 初始化应用数据
31        initializeApplicationData();
32        
33        log.info("✅ 应用启动任务完成");
34    }
35    
36    private void performCommandLineTasks(String[] args) {
37        if (args.length > 0) {
38            log.info("命令行参数: {}", Arrays.toString(args));
39            
40            // 处理特定的命令行参数
41            if (Arrays.asList(args).contains("--init-db")) {
42                initializeDatabase();
43            }
44        }
45    }
46    
47    private void checkCriticalBeans() {
48        String[] criticalBeans = {
49            "dataSource", "entityManagerFactory", "transactionManager"
50        };
51        
52        for (String beanName : criticalBeans) {
53            if (context.containsBean(beanName)) {
54                log.info("✅ 关键Bean已就绪: {}", beanName);
55            } else {
56                log.warn("⚠️ 缺少关键Bean: {}", beanName);
57            }
58        }
59    }
60    
61    @Override
62    public int getOrder() {
63        return 1; // 执行顺序
64    }
65}
66

🔧 启动故障诊断工具

​​启动问题诊断器​​:

1@Component
2@ConditionalOnProperty(name = "app.startup.diagnostic", havingValue = "true")
3@Slf4j
4public class StartupDiagnosticTool {
5    
6    @Autowired
7    private ApplicationContext context;
8    
9    @EventListener
10    public void diagnoseOnReady(ApplicationReadyEvent event) {
11        log.info("=== 启动故障诊断开始 ===");
12        
13        // 1. 检查Bean定义冲突
14        checkBeanDefinitionConflicts();
15        
16        // 2. 检查循环依赖
17        checkCircularDependencies();
18        
19        // 3. 检查配置属性
20        checkConfigurationProperties();
21        
22        // 4. 检查数据库连接
23        checkDatabaseConnection();
24        
25        log.info("=== 启动故障诊断完成 ===");
26    }
27    
28    private void checkBeanDefinitionConflicts() {
29        try {
30            if (context instanceof ConfigurableApplicationContext) {
31                ConfigurableListableBeanFactory beanFactory = 
32                    ((ConfigurableApplicationContext) context).getBeanFactory();
33                
34                // 检查重复的Bean定义
35                String[] beanNames = beanFactory.getBeanDefinitionNames();
36                Map<String, List<String>> typeToBeanNames = new HashMap<>();
37                
38                for (String beanName : beanNames) {
39                    BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
40                    String className = bd.getBeanClassName();
41                    if (className != null) {
42                        typeToBeanNames.computeIfAbsent(className, k -> new ArrayList<>())
43                                      .add(beanName);
44                    }
45                }
46                
47                // 报告冲突
48                typeToBeanNames.entrySet().stream()
49                    .filter(entry -> entry.getValue().size() > 1)
50                    .forEach(entry -> log.warn("🔴 Bean定义冲突: {} -> {}", 
51                        entry.getKey(), entry.getValue()));
52            }
53        } catch (Exception e) {
54            log.warn("Bean定义冲突检查失败: {}", e.getMessage());
55        }
56    }
57    
58    // 其他检查方法...
59}
60

💎 八、总结:从 main() 到容器就绪的生命线

🎯 Spring Boot 启动流程核心总结

​​启动阶段关键节点回顾​​:

阶段关键方法主要工作发布事件
初始化阶段SpringApplication 构造函数推断 Web 应用类型(Servlet、Reactive)、加载 ApplicationContextInitializer 与 ApplicationListener
环境准备阶段prepareEnvironment()构建 ConfigurableEnvironment,加载配置文件与系统属性,合并命令行参数ApplicationEnvironmentPreparedEvent
创建上下文阶段createApplicationContext()实例化具体类型的 ApplicationContext(如 AnnotationConfigServletWebServerApplicationContext)ApplicationContextInitializedEvent
上下文准备阶段prepareContext()应用 ApplicationContextInitializer,注册核心单例 Bean(如 springApplicationArguments)ApplicationPreparedEvent
上下文刷新阶段refreshContext()加载 Bean 定义、创建单例 Bean、初始化容器生命周期ContextRefreshedEvent
启动完成阶段afterRefresh()执行 ApplicationRunner 与 CommandLineRunner,发布应用就绪事件ApplicationReadyEvent

🔄 启动流程完整时序图

​​Spring Boot 应用启动完整流程​​:

User main() SpringApplication EventListener ApplicationContext BeanFactory Runner 执行java -jar SpringApplication.run() 阶段1: 初始化 推断应用类型 加载Initializer/Listener ApplicationStartingEvent 阶段2: 环境准备 创建Environment 处理配置属性 ApplicationEnvironmentPreparedEvent 阶段3: 上下文创建 创建ApplicationContext 应用Initializer ApplicationContextInitializedEvent 阶段4: 上下文准备 准备上下文 注册单例Bean ApplicationPreparedEvent 阶段5: 刷新上下文 refresh() 加载Bean定义 实例化单例 ContextRefreshedEvent 阶段6: 启动完成 执行Runner ApplicationStartedEvent ApplicationReadyEvent 返回ApplicationContext 应用启动成功 User main() SpringApplication EventListener ApplicationContext BeanFactory Runner

🚀 性能优化建议

​​启动性能优化策略​​:

1@SpringBootApplication
2public class OptimizedApplication {
3    
4    public static void main(String[] args) {
5        SpringApplication app = new SpringApplication(OptimizedApplication.class);
6        
7        // 1. 配置优化选项
8        app.setLazyInitialization(true); // 启用懒加载
9        app.setBannerMode(Banner.Mode.CONSOLE); // 控制Banner输出
10        
11        // 2. 排除不必要的自动配置
12        app.setDefaultProperties(Collections.singletonMap(
13            "spring.autoconfigure.exclude", 
14            "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"
15        ));
16        
17        app.run(args);
18    }
19    
20    @Configuration
21    @ConditionalOnProperty(name = "app.optimization.enabled", havingValue = "true")
22    public static class OptimizationConfig {
23        
24        @Bean
25        public StartupOptimizer startupOptimizer() {
26            return new StartupOptimizer();
27        }
28    }
29}
30

🔧 调试与监控最佳实践

​​生产环境启动监控配置​​:

1# application-prod.properties
2# 启动性能监控
3management.endpoints.web.exposure.include=health,info,metrics,startup
4management.endpoint.startup.enabled=true
5
6# 详细的启动日志
7logging.level.org.springframework.boot=INFO
8logging.level.com.example=DEBUG
9
10# 启动超时设置
11spring.boot.startup.timeout=300s
12
13# 懒加载配置
14spring.main.lazy-initialization=true
15
16# 排除不必要的自动配置
17spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
18

Spring Boot 启动流程源码解析》 是转载文章,点击查看原文


相关推荐


BUYCOIN:以社区共治重构加密交易版图,定义交易所3.0时代
焦点链创研究所2025/10/25

2025年,全球加密市场在合规化浪潮与信任重建需求的双重驱动下,正经历一场深刻的范式革命。当FTX暴雷事件的余波仍在引发行业对中心化模式的反思,当传统交易所“少数人受益”的分配壁垒愈发凸显,持有美国MSB合规牌照的BUYCOIN交易所横空出世。它以“非托管架构+DAO治理”为双引擎,以“全民持股”为核心内核,不仅破解了传统交易所的信任难题与价值分配困局,更在加密行业迈入万亿美元规模的关键节点,为全球用户勾勒出“共建、共治、共享”的交易新生态。 破局者登场:瞄准行业沉疴的范式革新 当前加密市场呈


UVa 1660 Cable TV Network
寂静山林2025/10/22

题目描述 给定一个双向连接的有线电视网络,网络由中继器(节点)和电缆(边)组成。网络连通的定义是:任意两个节点之间至少存在一条路径。安全系数 fff 的定义如下: 如果无论删除多少个节点(只要不全部删除),网络都保持连通,则 f=nf = nf=n(nnn 为节点数)。 否则,fff 等于能够使网络断开的最小删除节点数。 注意: 空网络(n=0n = 0n=0)或单节点网络(n=1n = 1n=1)视为连通。 输入数据保证正确,节点数 n≤50n \leq 50n


Android studio 修改包名
lichong9512025/10/22

在 Android Studio 里把 package="com.fhvideo.phone" 整体改掉(例如换成 com.mycompany.newapp)分两步走: 让 源码目录结构 和 package 声明 一致让 build.gradle 的 applicationId 与 AndroidManifest.xml 的 package 同步(否则安装时会当成全新应用) 下面给出 最简无坑流程,全程 2-3 min,复制即可用。 一、一键重命名(IDE 自带) 切到 Projec


闲谈KubeBlocks For MongoDB设计实现
小猿姐2025/10/20

闲谈KubeBlocks For MongoDB设计实现 引言 MongoDB 是目前最受欢迎的 NoSQL 数据库之一,这跟它的多种特性有关,如面向文档、高性能、易使用等等,业务使用较为友好。不过由于它本身的复杂性,如节点多状态、多拓扑结构等,使得 MongoDB 的运维管理较为困难。在 K8S 环境下,由于资源的灵活编排,网络的隔离限制,进一步增加了 MongoDB 云原生化的难度,本文将从以下几点阐述 KubeBlocks For MongoDB 在设计实现过程中遇到的难点及解决方案,让大


复杂结构数据挖掘(二)关联规则挖掘 Association rule mining
nju_spy2025/10/19

你是否曾好奇,为什么超市总把啤酒和尿布摆在一起?这看似随意的陈列背后,藏着数据挖掘领域的经典智慧 —— 关联规则挖掘。在大数据时代,海量交易记录如同未开垦的金矿,而关联规则正是撬开这座金矿的关键工具。想象一下,当你在电商平台浏览商品时,系统推荐的 "买了这个的人还买了...",或是超市根据消费数据优化的货架布局,这些场景背后都离不开关联规则算法的神奇魔力。         从本质上讲,关联规则挖掘要解决的核心问题,是在庞大的交易数据中找出 "X→Y" 这样的隐含关系 —— 例如 "买了面包的人


程序员必备!5 款免费又好用的数据库管理工具推荐
追逐时光者2025/10/18

前言 在数据驱动的时代,数据库管理工具对于程序员而言如同瑞士军刀般不可或缺。它们不仅能够帮助我们高效地管理数据库,还能提升数据处理的准确性和速度。今天大姚给大家分享 5 款免费且实用的数据库管理工具(排名不分先后,欢迎文末留下你常用的数据库管理工具),希望可以帮助到有需要的同学。 DataGrip DataGrip 是 JetBrains 推出的一款跨平台(在 Windows、macOS 和 Linux 上提供一致的体验)数据库 IDE,专为 SQL 开发与数据库管理而打造。它集智能代码补全、A


kotlin中MutableStateFlow和MutableSharedFlow的区别是什么?
AsiaLYF2025/10/16

在 Kotlin 的协程库(kotlinx.coroutines.flow)中,MutableStateFlow 和 MutableSharedFlow 都是用于构建响应式数据流的可变(Mutable)热流(Hot Flow),但它们的设计目标和行为特性有显著区别。以下是它们的核心对比: 1. 核心区别总结 特性MutableStateFlowMutableSharedFlow数据保留始终保存最新一个值(必须有初始值)不保留值(默认),但可配置缓冲区保留历史值订阅时机新订阅者立即收到当前最新


组合为什么优于继承:从工程实践到数学本质
canonical_entropy2025/10/15

在面向对象设计的殿堂里,"组合优于继承"(Composition over Inheritance)是一条近乎金科玉律的原则。每一位有经验的开发者都会告诫新手:优先使用组合,谨慎使用继承。但这背后的原因究竟是什么?仅仅是因为组合更加灵活吗?答案远不止于此。这种设计偏好的背后,实际上隐藏着深刻的数学原理,它关乎系统结构的稳定性、可预测性和长期可维护性。 第一部分:工程实践的智慧结晶 在日常编程实践中,我们对"组合优于继承"有着直观而实用的理解。 继承的"白盒"困境 继承建立了一种"is-a"(是一


这份超全JavaScript函数指南让你从小白变大神
良山有风来2025/10/14

你是不是曾经看着JavaScript里各种函数写法一头雾水?是不是经常被作用域搞得晕头转向?别担心,今天这篇文章就是要帮你彻底搞懂JavaScript函数! 读完本文,你将收获: 函数的各种写法和使用场景 参数传递的底层逻辑 作用域和闭包的彻底理解 箭头函数的正确使用姿势 准备好了吗?让我们开始这场函数探险之旅! 函数基础:从“Hello World”开始 先来看最基础的函数声明方式: // 最传统的函数声明 function sayHello(name) { return "Hello


武装你的Python“工具箱”:盘点10个你必须熟练掌握的核心方法
烛阴2025/10/12

一、字符串方法 字符串处理是我们日常编程中最高频的操作之一。 .strip() - 去除首尾空白 示例: user_input = " admin \n" cleaned_input = user_input.strip() print(f"清理前: '{user_input}', 清理后: '{cleaned_input}'") # 输出: #清理前: ' admin #', 清理后: 'admin' .split() - 字符串切割 示例: csv_line =

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0