网站建设服务亮点,企业网络营销方案设计,wordpress整合,网络营销是什么前言在上一篇中#xff0c;我们已经成功搭建了Spring Boot源码研究环境。现在#xff0c;让我们深入Spring Boot的核心——启动过程。当你运行一个Spring Boot应用的main方法时#xff0c;背后究竟发生了什么#xff1f;本文将带你从SpringApplication.run()开始#xff0…前言在上一篇中我们已经成功搭建了Spring Boot源码研究环境。现在让我们深入Spring Boot的核心——启动过程。当你运行一个Spring Boot应用的main方法时背后究竟发生了什么本文将带你从SpringApplication.run()开始一步步揭开Spring Boot启动的神秘面纱。在正式开始介绍之前先用形象的方式类比SpringApplication这个类用途。0、把SpringApplication想象成汽车制造工厂public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) {这就像在说我们要建造一个汽车制造工厂这是我们的原料供应商(resourceLoader)和核心设计图纸(primarySources) 一步步拆解这个汽车工厂的建造过程1.接收核心设计图纸this.primarySources new LinkedHashSet(Arrays.asList(primarySources));通俗解释工厂收到你给的核心设计图纸就是你的SpringBootApplication主类。比如你传入了DemoApplication.class工厂就知道哦我要按照这个设计来造车2.判断要造什么类型的车this.properties.setWebApplicationType(WebApplicationType.deduceFromClasspath());通俗解释工厂自动检查你的零件仓库类路径判断你要造什么车发现有Servlet零件 → 造传统Web汽车SERVLET发现有WebFlux零件 → 造新能源响应式汽车REACTIVE什么Web零件都没有 → 造普通家用轿车NONE3.招聘第一批基础工人this.bootstrapRegistryInitializers new ArrayList( getSpringFactoriesInstances(BootstrapRegistryInitializer.class));通俗解释工厂先招聘地基施工队BootstrapRegistryInitializer这些工人在工厂刚建好时就进场负责打地基、铺管线等最基础的工作。4.招聘车间主任和质检员setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));通俗解释接着招聘车间主任ApplicationContextInitializer他们负责在各个车间ApplicationContext正式开工前检查设备、调整生产线布局。5.安装监控摄像头和警报器setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));通俗解释安装监控系统ApplicationListener这些耳朵会监听工厂里发生的各种事件机器启动、零件到位、故障报警等。6.确定总设计师办公室this.mainApplicationClass deduceMainApplicationClass();通俗解释自动找到总设计师的办公室主应用类这样工厂有任何问题都知道该找谁汇报。 完整造车流程比喻想象一下整个Spring Boot启动就像造一辆汽车设计阶段SpringApplication构造器拿到设计图纸primarySources决定造什么车WebApplicationType招聘各种工人各种Initializer和Listener生产线准备run()方法开始地基工人进场BootstrapRegistryInitializer车间主任检查设备ApplicationContextInitializer启动监控系统ApplicationListener正式生产refresh()方法零件生产线运转Bean创建组装整车Bean依赖注入质量检测Bean后置处理出厂上路启动完成汽车可以开了应用可以接收请求监控系统持续工作事件监听 给新手的核心理解要点为什么要有这么多工人分工明确每个工人只负责自己的专业领域可扩展性你可以自己招聘新工人自定义Initializer/Listener生命周期管理工人们按照固定顺序工作不会乱套这个构造器的作用总结// 用一句话总结这个构造器 收集所有必要的工具和工人为后续的汽车制造做好准备下一步会发生什么构造器只是准备工作真正的造车是在run()方法中// 准备工作完成开始造车 SpringApplication.run(DemoApplication.class, args); 形象记忆技巧把SpringApplication想象成resourceLoader 原料供应商primarySources 核心设计图纸BootstrapRegistryInitializer 地基施工队ApplicationContextInitializer 车间主任ApplicationListener 监控摄像头mainApplicationClass 总设计师办公室这样下次看到这段代码你就能立即在脑海中构建出这个汽车工厂的生动画面了理解了这个比喻后续学习run()方法时就会轻松很多因为那只是按部就班地执行这个造车流程而已。1. SpringApplication初始化启动的起点1.1 入口点分析让我们从最简单的Spring Boot应用开始SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }关键源码位置spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java接下来用一个非常形象的比喻来理解SpringApplication的作用和执行流程。1.2 构造器初始化过程// SpringApplication构造器核心逻辑 public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) { this.resourceLoader resourceLoader; this.primarySources new LinkedHashSet(Arrays.asList(primarySources)); // 关键步骤1推断Web应用类型 this.webApplicationType WebApplicationType.deduceFromClasspath(); // 关键步骤2加载应用上下文初始化器 setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 关键步骤3加载应用事件监听器 setListeners(getSpringFactoriesInstances(ApplicationListener.class)); // 关键步骤4推断主应用类 this.mainApplicationClass deduceMainApplicationClass(); }1.3 Web应用类型推断// WebApplicationType.deduceFromClasspath() 源码分析 static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; // 响应式Web应用 } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; // 非Web应用 } } return WebApplicationType.SERVLET; // Servlet Web应用 }调试技巧在deduceFromClasspath()方法设置断点观察类路径检测逻辑。2. run方法执行流程启动的核心2.1 run方法整体架构public ConfigurableApplicationContext run(String... args) { // 1. 启动计时器 StopWatch stopWatch new StopWatch(); stopWatch.start(); // 2. 创建引导上下文和应用上下文 ConfigurableApplicationContext context null; CollectionSpringBootExceptionReporter exceptionReporters new ArrayList(); configureHeadlessProperty(); // 3. 获取SpringApplicationRunListeners SpringApplicationRunListeners listeners getRunListeners(args); // 4. 发布ApplicationStartingEvent事件 listeners.starting(); try { // 5. 准备环境 ApplicationArguments applicationArguments new DefaultApplicationArguments(args); ConfigurableEnvironment environment prepareEnvironment(listeners, applicationArguments); // 6. 打印Banner Banner printedBanner printBanner(environment); // 7. 创建应用上下文 context createApplicationContext(); // 8. 准备应用上下文 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 9. 刷新上下文Spring核心流程 refreshContext(context); // 10. 后置处理 afterRefresh(context, applicationArguments); // 11. 停止计时器 stopWatch.stop(); // 12. 发布启动完成事件 if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); // 13. 执行Runner callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } listeners.running(context); return context; }2.2 环境准备阶段private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 创建和配置环境 ConfigurableEnvironment environment getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); // 发布EnvironmentPreparedEvent事件 listeners.environmentPrepared(environment); // 绑定环境到SpringApplication bindToSpringApplication(environment); // 转换环境如果需要 if (!this.isCustomEnvironment) { environment new EnvironmentConverter(getClassLoader()) .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } // 配置PropertySources ConfigurationPropertySources.attach(environment); return environment; }2.3 应用上下文创建protected ConfigurableApplicationContext createApplicationContext() { Class? contextClass this.applicationContextClass; if (contextClass null) { try { // 根据Web应用类型选择不同的上下文实现 switch (this.webApplicationType) { case SERVLET: contextClass Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException(Unable create a default ApplicationContext, please specify an ApplicationContextClass, ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }3. 上下文刷新Spring核心流程3.1 refreshContext核心流程// 这是Spring框架的核心方法Spring Boot进行了封装 private void refreshContext(ConfigurableApplicationContext context) { refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // 不在允许的环境中 } } } // 实际调用Spring的refresh方法 protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }3.2 Spring Framework的refresh方法// 在AbstractApplicationContext中定义包含12个关键步骤 public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 1. 准备刷新上下文 prepareRefresh(); // 2. 获取新的BeanFactory ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory(); // 3. 准备BeanFactory prepareBeanFactory(beanFactory); try { // 4. 后置处理BeanFactory postProcessBeanFactory(beanFactory); // 5. 调用BeanFactoryPostProcessors invokeBeanFactoryPostProcessors(beanFactory); // 6. 注册BeanPostProcessors registerBeanPostProcessors(beanFactory); // 7. 初始化MessageSource initMessageSource(); // 8. 初始化事件广播器 initApplicationEventMulticaster(); // 9. 初始化特殊Bean由子类实现 onRefresh(); // 10. 注册监听器 registerListeners(); // 11. 完成BeanFactory初始化实例化所有单例Bean finishBeanFactoryInitialization(beanFactory); // 12. 完成刷新过程发布ContextRefreshedEvent事件 finishRefresh(); } catch (BeansException ex) { // 清理资源 destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }3.3 Spring Boot的onRefresh扩展// 在SpringApplication中onRefresh方法被重写以支持Web服务器启动 protected void onRefresh(ApplicationContext context) { // 调用父类方法 super.onRefresh(context); // Spring Boot特有的创建Web服务器 if (context instanceof ConfigurableWebServerApplicationContext) { ((ConfigurableWebServerApplicationContext) context) .setServerNamespace(this.serverNamespace); } }4. 自动配置机制Spring Boot的魔法核心4.1 SpringBootApplication注解解析Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inherited SpringBootConfiguration EnableAutoConfiguration ComponentScan(excludeFilters { Filter(type FilterType.CUSTOM, classes TypeExcludeFilter.class), Filter(type FilterType.CUSTOM, classes AutoConfigurationExcludeFilter.class) }) public interface SpringBootApplication { // 省略属性定义 }4.2 EnableAutoConfiguration核心机制Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inherited AutoConfigurationPackage Import(AutoConfigurationImportSelector.class) public interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY spring.boot.enableautoconfiguration; Class?[] exclude() default {}; String[] excludeName() default {}; }4.3 AutoConfigurationImportSelector工作流程// 这是自动配置的核心类 public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 1. 获取自动配置条目 AutoConfigurationEntry autoConfigurationEntry getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { // 2. 检查自动配置是否启用 if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // 3. 获取注解属性 AnnotationAttributes attributes getAttributes(annotationMetadata); // 4. 获取候选配置 ListString configurations getCandidateConfigurations(annotationMetadata, attributes); // 5. 移除重复配置 configurations removeDuplicates(configurations); // 6. 根据exclude属性排除配置 SetString exclusions getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); // 7. 应用过滤条件 configurations getConfigurationClassFilter().filter(configurations); // 8. 触发自动配置导入事件 fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } protected ListString getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { // 从META-INF/spring.factories加载自动配置类 ListString configurations SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.); return configurations; } protected Class? getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; } }5. Web服务器启动内嵌容器的奥秘5.1 Servlet Web服务器启动// 在ServletWebServerApplicationContext中 Override protected void onRefresh() { super.onRefresh(); try { createWebServer(); // 创建Web服务器 } 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) { // 从BeanFactory获取WebServerFactory ServletWebServerFactory factory getWebServerFactory(); // 创建WebServer 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(); }5.2 Tomcat服务器创建过程// 在TomcatServletWebServerFactory中 Override public WebServer getWebServer(ServletContextInitializer... initializers) { // 1. 创建Tomcat实例 Tomcat tomcat new Tomcat(); // 2. 配置基础目录 File baseDir (this.baseDirectory ! null) ? this.baseDirectory : createTempDir(tomcat); tomcat.setBaseDir(baseDir.getAbsolutePath()); // 3. 创建Connector Connector connector new Connector(this.protocol); tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); // 4. 创建Engine和Host tomcat.getHost().setAutoDeploy(false); configureEngine(tomcat.getEngine()); // 5. 准备Context prepareContext(tomcat.getHost(), initializers); // 6. 返回自定义的TomcatWebServer return getTomcatWebServer(tomcat); }6. 启动扩展点自定义启动行为6.1 ApplicationRunner vs CommandLineRunner// ApplicationRunner示例 Component Order(1) // 指定执行顺序 public class DemoApplicationRunner implements ApplicationRunner { Override public void run(ApplicationArguments args) throws Exception { System.out.println(ApplicationRunner执行参数: Arrays.toString(args.getSourceArgs())); // 应用启动后需要执行的逻辑 } } // CommandLineRunner示例 Component Order(2) public class DemoCommandLineRunner implements CommandLineRunner { Override public void run(String... args) throws Exception { System.out.println(CommandLineRunner执行参数: Arrays.toString(args)); // 应用启动后需要执行的逻辑 } }6.2 应用事件监听机制// 监听应用启动事件 Component public class ApplicationStartupListener implements ApplicationListenerApplicationStartedEvent { private static final Logger logger LoggerFactory.getLogger(ApplicationStartupListener.class); Override public void onApplicationEvent(ApplicationStartedEvent event) { logger.info(应用启动完成开始执行初始化任务...); // 执行自定义初始化逻辑 performInitialization(); } private void performInitialization() { // 初始化缓存、连接池等 } }7. 调试与实验验证启动过程7.1 创建调试配置在IDEA中创建调试配置添加以下VM参数-Ddebugtrue -Dspring.output.ansi.enabledALWAYS7.2 关键断点设置建议设置断点观察启动流程SpringApplication构造器SpringApplication.run()方法入口prepareEnvironment()方法createApplicationContext()方法refreshContext()方法onRefresh()方法Web服务器启动7.3 启动日志分析启用debug日志观察启动细节# application.properties logging.level.org.springframework.bootDEBUG logging.level.org.springframework.contextDEBUG8. 启动过程总结与核心流程图8.1 启动过程核心步骤8.2 关键设计模式应用模板方法模式AbstractApplicationContext.refresh()定义了算法骨架观察者模式Spring事件机制工厂模式ApplicationContext创建策略模式不同的Web应用类型处理责任链模式BeanPostProcessor调用链结语通过本文的深入分析我们揭示了Spring Boot启动过程的完整流程。从SpringApplication初始化到Web服务器启动每一个步骤都体现了Spring Boot约定大于配置的设计哲学。关键收获Spring Boot启动是Spring Framework生命周期与Boot特有扩展的结合自动配置通过SpringFactoriesLoader机制实现Web服务器启动在onRefresh阶段触发事件机制为启动过程提供了丰富的扩展点下篇预告在下一篇文章中我们将深入Spring Boot的自动配置机制解析Conditional注解体系并学习如何编写自定义的Starter。思考题如果在启动过程中需要读取配置文件中的自定义配置应该在哪个阶段进行如何在不修改源码的情况下在Bean创建前后插入自定义逻辑Spring Boot如何支持多种内嵌Web服务器Tomcat、Jetty、Undertow的自动切换欢迎在评论区分享你的理解和遇到的问题