SpringBoot 是一个基于 Spring 框架的疾速开发框架,旨在简化 Spring 应用程序的开发和部署。在本文中,咱们将深入分析 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 如何简化应用程序的开发和部署。