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
方法来通知应用程序环境已经准备好了。
在前一步骤中,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启动流程是什么的详细内容。更多信息请关注PHP中文网其他相关文章!