SpringBoot 之启动流程详解
作者:这堆干货有点猛
SpringBoot启动过程简介
SpringBoot应用程序的启动过程可以分为以下几个步骤:
- 加载应用程序上下文
- 扫描应用程序中的所有组件
- 自动配置应用程序环境
- 启动嵌入式Web服务器
在下面的章节中,我们将逐一分析这些步骤的源代码。
加载应用程序上下文
SpringBoot 应用程序的上下文是一个包含所有应用程序组件的容器。在启动过程中,SpringBoot 会加载并初始化这个容器。
这个步骤的源代码在SpringApplication
类中。具体来说,SpringApplication
类的run
方法是这个过程的入口点。在这个方法中,Spring Boot会通过调用createApplicationContext
方法来创建应用程序上下文。
下面是createApplicationContext
方法的源代码:
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { 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 to create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
在这个方法中,SpringBoot 会根据应用程序类型(Servlet或Reactive)选择合适的上下文类。然后,它会使用 Java 反射机制来实例化这个类并返回一个可配置的应用程序上下文对象。
扫描应用程序中的所有组件
在上一步中,SpringBoot创建了应用程序上下文。在这一步中,SpringBoot会扫描应用程序中的所有组件并将它们注册到应用程序上下文中。
这个步骤的源代码在SpringApplication
类中的scan
方法中。具体来说,在这个方法中,SpringBoot 会创建一个SpringBootBeanDefinitionScanner
对象,并使用它来扫描应用程序中的所有组件。
下面是scan
方法的源代码:
private void scan(String... basePackages) { if (ObjectUtils.isEmpty(basePackages)) { return; } ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider( this.includeFilters, this.excludeFilters, this.resourceLoader); scanner.setResourceLoader(this.resourceLoader); scanner.setEnvironment(this.environment); scanner.setIncludeAnnotationConfig(this.useAnnotatedConfig); scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) { @Override protected boolean matchClassName(String className) { return getExcludeClassNames().contains(className); } }); for (String basePackage : basePackages) { scanner.findCandidateComponents(basePackage).forEach(this.componentDefinitions::add); } }
在这个方法中,SpringBoot 会创建一个ClassPathScanningCandidateComponentProvider
对象,并使用它来扫描应用程序中的所有组件。这个对象会扫描指定包路径下的所有类,并将它们转换为 Spring 的 Bean 定义。这些 Bean 定义将被注册到应用程序上下文中。
自动配置应用程序环境
在上一步中,SpringBoot将应用程序中的所有组件注册到应用程序上下文中。在这一步中,SpringBoot将自动配置应用程序环境,包括配置数据源、事务管理器、JPA等。
这个步骤的源代码在SpringApplication
类中的configureEnvironment
方法中。在这个方法中,Spring Boot会创建一个SpringApplicationRunListeners
对象,并使用它来配置应用程序环境。
下面是configureEnvironment
方法的源代码:
private void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addCommandLineProperties) { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); environment.getPropertySources().addLast(new CommandLinePropertySource(applicationArguments)); } this.listeners.environmentPrepared(environment); if (this.logStartupInfo) { this.logStartupInfo(environment); } ConfigurationPropertySources.attach(environment); Binder.get(environment).bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(this.sources)); if (!this.isCustomEnvironment) { EnvironmentConverter.configureEnvironment(environment, this.deduceEnvironmentClass()); } this.listeners.environmentPrepared(environment); }
在这个方法中,SpringBoot 会创建一个ApplicationArguments
对象,并将其转换为一个命令行属性源。然后,它会调用listeners
中的environmentPrepared
方法来通知应用程序环境已经准备好了。随后,SpringBoot 会绑定属性源到应用程序环境中,并调用listeners
中的environmentPrepared
方法来通知应用程序环境已经准备好了。
启动嵌入式Web服务器
在上一步中,SpringBoot 将应用程序环境自动配置完成。在这一步中,SpringBoot 将启动嵌入式Web服务器,以便应用程序能够提供 Web 服务。
这个步骤的源代码在SpringApplication
类中的run
方法中。具体来说,在这个方法中,SpringBoot 会根据应用程序类型(Servlet或Reactive)选择合适的嵌入式Web服务器,并使用它来启动应用程序。
下面是run
方法的源代码:
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
在这个方法中,SpringBoot 会使用一个StopWatch
对象来计算应用程序启动时间。然后,它会调用listeners
中的starting
方法来通知应用程序即将启动。接着,SpringBoot 会准备应用程序环境,并使用它来创建应用程序上下文。随后,SpringBoot 会调用listeners
中的started
方法来通知应用程序已经启动。最后,SpringBoot 会调用callRunners
方法来运行所有的CommandLineRunner
和ApplicationRunner
组件。
总结
在本文中,我们深入分析了 SpringBoot 应用程序的启动过程的源代码。我们了解了 SpringBoot 如何加载应用程序上下文、扫描应用程序中的所有组件、自动配置应用程序环境以及启动嵌入式Web服务器。这些步骤的源代码展示了 SpringBoot 如何简化应用程序的开发和部署。
以上就是SpringBoot 之启动流程详解的详细内容,更多关于SpringBoot启动流程的资料请关注脚本之家其它相关文章!