新闻详情

新闻详情

首页 / 资讯中心 / 详情

SpringBoot启动流程深度解析与性能优化实践

发布时间:2026/9/21 17:40:28来源:尧图网络
SpringBoot启动流程深度解析与性能优化实践
1. SpringBoot启动过程全景透视当我们在IDE中点击运行那个标注了SpringBootApplication的main()方法时背后究竟发生了什么这个看似简单的启动动作实际上触发了一个精密的连锁反应机制。作为Java生态中最主流的应用框架SpringBoot的启动流程设计体现了约定优于配置的核心思想通过自动化装配机制将开发者从繁琐的XML配置中解放出来。我曾在多个微服务项目中追踪过SpringBoot的启动日志发现即便是同一个应用在不同环境下的启动过程也存在微妙差异。这促使我深入源码层面去理解从main()方法执行到应用完全就绪期间那些隐藏在表面之下的关键节点。本文将基于SpringBoot 2.7.x版本带你拆解这个黑盒中的每个精密齿轮。2. 启动流程阶段拆解2.1 初始化阶段SpringApplication实例化当执行SpringApplication.run()时首先会创建SpringApplication实例。这个构造过程包含几个关键操作public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) { this.resourceLoader resourceLoader; this.primarySources new LinkedHashSet(Arrays.asList(primarySources)); this.webApplicationType WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers new ArrayList( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass deduceMainApplicationClass(); }这里有几个设计亮点值得注意Web应用类型推断WebApplicationType通过检查类路径下是否存在特定类如Servlet、Reactive相关类来自动判断应用是ServletWeb、ReactiveWeb还是普通应用通过SpringFactoriesLoader加载META-INF/spring.factories中定义的扩展点实现这是SpringBoot自动装配的基础机制主类推断算法会遍历调用栈寻找包含main()方法的类实际项目中常见的一个坑是当存在多个main类时deduceMainApplicationClass()可能返回错误结果。这时建议显式设置mainApplicationClass。2.2 运行阶段SpringApplication.run()run()方法是整个启动过程的核心枢纽其执行流程可以概括为public ConfigurableApplicationContext run(String... args) { long startTime System.nanoTime(); DefaultBootstrapContext bootstrapContext createBootstrapContext(); ConfigurableApplicationContext context null; configureHeadlessProperty(); SpringApplicationRunListeners listeners getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments new DefaultApplicationArguments(args); ConfigurableEnvironment environment prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner printBanner(environment); context createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); Duration timeTakenToStartup Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), timeTakenToStartup); } listeners.started(context, timeTakenToStartup); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }2.2.1 环境准备阶段prepareEnvironment()方法完成了几个重要工作根据webApplicationType创建对应的Environment实例StandardServletEnvironment/StandardReactiveWebEnvironment等处理命令行参数--server.port8080等形式加载所有配置源application.properties/yml、系统属性、环境变量等发布ApplicationEnvironmentPreparedEvent事件这里有个性能优化点配置文件的加载顺序会影响属性覆盖规则但过多的配置源会延长启动时间。生产环境中建议明确指定active profiles。2.2.2 上下文创建阶段createApplicationContext()根据应用类型创建不同的ApplicationContextAnnotationConfigServletWebServerApplicationContextServlet Web应用AnnotationConfigReactiveWebServerApplicationContextReactive Web应用AnnotationConfigApplicationContext普通应用这个阶段会初始化Bean定义读取器AnnotatedBeanDefinitionReader和类路径扫描器ClassPathBeanDefinitionScanner为后续的组件扫描做准备。2.2.3 上下文准备阶段prepareContext()完成了几个关键操作注册主配置类SpringBootApplication标注的类作为bean定义应用所有ApplicationContextInitializer发布ApplicationContextInitializedEvent事件注册特定的单例bean如Banner、ApplicationArguments开发自定义starter时常通过ApplicationContextInitializer来执行前置操作。但要注意初始化的顺序依赖问题。3. 容器刷新机制解析refreshContext()最终会调用AbstractApplicationContext.refresh()这是Spring容器初始化的核心流程public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { StartupStep contextRefresh this.applicationStartup.start(spring.context.refresh); prepareRefresh(); ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); StartupStep beanPostProcess this.applicationStartup.start(spring.context.beans.post-process); invokeBeanFactoryPostProcessors(beanFactory); beanPostProcess.end(); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } // ... 异常处理 contextRefresh.end(); } }3.1 BeanFactory后置处理invokeBeanFactoryPostProcessors()是自动装配的核心实现点它会处理ConfigurationClassPostProcessor解析Configuration类处理ComponentScan、Import等注解BeanDefinitionRegistryPostProcessor允许编程式注册额外的bean定义各种BeanFactoryPostProcessor修改已注册的bean定义SpringBoot的自动装配魔法主要在这里实现。以SpringBootApplication为例它组合了EnableAutoConfiguration后者会通过AutoConfigurationImportSelector加载META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中定义的自动配置类。3.2 Bean后置处理器注册registerBeanPostProcessors()会实例化并注册所有BeanPostProcessor这些处理器将在bean实例化过程中介入。常见的后置处理器包括AutowiredAnnotationBeanPostProcessor处理Autowired注入CommonAnnotationBeanPostProcessor处理Resource等JSR-250注解PersistenceAnnotationBeanPostProcessor处理JPA相关注解在自定义starter开发中BeanPostProcessor是扩展容器功能的常用手段。但要注意处理器之间的执行顺序问题。3.3 单例Bean预实例化finishBeanFactoryInitialization()会实例化所有非懒加载的单例bean这是启动过程中最耗时的阶段之一。该过程采用智能初始化策略首先处理BeanPostProcessor和FactoryBean然后按依赖顺序初始化其他bean对循环依赖有特殊处理三级缓存机制4. 内嵌Web服务器启动流程对于Web应用onRefresh()会触发内嵌服务器的启动。以Tomcat为例protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException(Unable to start web server, ex); } } private void createWebServer() { WebServer webServer this.webServer; ServletContext servletContext getServletContext(); if (webServer null servletContext null) { ServletWebServerFactory factory getWebServerFactory(); this.webServer factory.getWebServer(getSelfInitializer()); } else if (servletContext ! null) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException(Cannot initialize servlet context, ex); } } initPropertySources(); }服务器启动的关键步骤包括从ServletWebServerApplicationContext获取ServletWebServerFactory自动配置的Tomcat/Jetty/Undertow工厂初始化DispatcherServlet并注册到Servlet容器启动Web服务器线程注册Shutdown Hook实际项目中经常需要定制内嵌服务器参数。除了通过application.properties配置外还可以通过WebServerFactoryCustomizer进行编程式配置。5. 启动性能优化实践根据对启动流程的分析我们可以针对性优化5.1 组件扫描优化SpringBootApplication(scanBasePackages com.myapp) public class Application { // 明确指定扫描范围避免全包扫描 }5.2 延迟初始化spring.main.lazy-initializationtrue5.3 自动配置排除SpringBootApplication(exclude { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })5.4 类加载优化使用Spring Boot 2.4的分层索引技术在Maven插件中配置build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration layers enabledtrue/enabled /layers /configuration /plugin /plugins /build6. 调试与问题排查当启动过程出现异常时可以增加调试日志logging.level.org.springframeworkDEBUG logging.level.org.springframework.bootTRACE使用启动监听器记录时间消耗public class StartupMonitor implements ApplicationListenerApplicationReadyEvent { Override public void onApplicationEvent(ApplicationReadyEvent event) { ApplicationStartup startup event.getApplicationContext().getApplicationStartup(); // 分析启动步骤耗时 } }检查自动配置决策debugtrue通过以上方法可以准确定位启动过程中的性能瓶颈或配置错误。在我的实践中约70%的启动问题都与自动配置或组件扫描相关。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

3步搞定数控加工仿真软件图解原理与源码避坑 2026/9/22 15:10:02

3步搞定数控加工仿真软件图解原理与源码避坑

3步搞定数控加工仿真软件图解原理与源码避坑 昨晚调试数控加工仿真软件,控制台直接喷出一脸 NullPointerException 。 StackTrace 长到拖屏都装不下,堆栈信息里全是…

阅读更多 →
3个核心模块搞定shallwetalk,面试必问的实战项目 2026/9/22 15:09:47

3个核心模块搞定shallwetalk,面试必问的实战项目

3个核心模块搞定shallwetalk,面试必问的实战项目 官方文档翻了三遍还是云里雾里?别急,我直接把坑都踩完了。 面试必问的实时聊天场景,往往卡在消息同步和连接管理上。 今天咱们不聊虚的,直接上手搭一个可运行的 shallwetalk…

阅读更多 →
3个menuitem高频坑 2026最新面试必问点 2026/9/22 15:09:47

3个menuitem高频坑 2026最新面试必问点

3个menuitem高频坑 2026最新面试必问点 面试官盯着你的简历问:“说说你对菜单组件的理解,特别是交互细节。”你心里一紧,脑子里全是 el-menu 或 ant-design 的 API…

阅读更多 →
3个实战技巧一文搞懂美华博客性能优化避坑指南 2026/9/22 15:09:34

3个实战技巧一文搞懂美华博客性能优化避坑指南

3个实战技巧一文搞懂美华博客性能优化避坑指南 盯着屏幕满屏飘红的 StackTrace,那种心累感谁懂?堆栈信息长得像天书,根本找不到报错源头。今天不讲虚的,直接带你一文搞懂如何在真实项目中通过性能优化干掉这些莫名其妙的卡顿和崩溃。…

阅读更多 →
CSS压缩源码深度解析:从入门到精通的避坑指南 2026/9/22 15:09:28

CSS压缩源码深度解析:从入门到精通的避坑指南

CSS压缩源码深度解析:从入门到精通的避坑指南 刚接手新项目,复制了一段网上流行的 CSS 压缩代码,结果页面直接崩了?样式全乱,控制台报错一片红,想调都找不到头。这种“拿来主义”翻车现场,在咱们开发圈里太常见了。想从入门到精通,光靠抄代码…

阅读更多 →
5个细节手写实现史蒂夫科尔,告别StackTrace崩溃 2026/9/22 15:09:14

5个细节手写实现史蒂夫科尔,告别StackTrace崩溃

5个细节手写实现史蒂夫科尔,告别StackTrace崩溃 看着满屏红色的 java.lang.NullPointerException 或者 IndexOutOfBoundsException…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞