Spring Boot 启动原理完整解析
Spring Boot 是一个能够快速构建独立的、生产级别的 Spring 应用的框架。它的启动过程涉及多个核心组件和设计模式。以下是对 Spring Boot 启动原理的详细解析,并结合关键源码来解释设计模式和常见面试问题点。
1. 启动类与注解解析
Spring Boot 应用通常由一个带有 @SpringBootApplication
注解的主启动类启动。@SpringBootApplication
是一个复合注解,主要由以下三个注解构成:
- @EnableAutoConfiguration:负责自动配置 Spring 应用上下文,加载符合条件的
@Configuration
配置类。 - @SpringBootConfiguration:标记当前类为 Spring 配置类,等同于
@Configuration
。 - @ComponentScan:自动扫描并加载符合条件的 Spring Bean。
源码分析:
// @SpringBootApplication 源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {
}
- @EnableAutoConfiguration:这个注解通过
@Import
引入了AutoConfigurationImportSelector
,该类负责从META-INF/spring.factories
文件中加载自动配置类。
// @EnableAutoConfiguration 源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
AutoConfigurationImportSelector 的关键方法:
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
设计模式:
- 装饰器模式:
@SpringBootApplication
通过组合多个注解来扩展功能,类似装饰器模式,为启动类添加了多个行为。
面试考点:
- 如何实现自定义自动配置?
@SpringBootApplication
中的各个注解的作用与区别是什么?- 如何精确控制 Spring Boot 的扫描路径?
2. SpringApplication 的构建与服务类型确定
SpringApplication.run()
是 Spring Boot 应用启动的入口。SpringApplication
是核心服务对象,构建过程包括:
- 资源加载器与主方法类的记录。
- 确定 Web 服务的类型,可能是
SERVLET
、REACTIVE
或NONE
。 - 加载
META-INF/spring.factories
文件中的BootstrapRegistryInitializer
、ApplicationContextInitializer
和ApplicationListener
配置。
构造方法源码:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
- ResourceLoader:用于加载资源。
- WebApplicationType:根据类路径中存在的类来推断当前应用的 Web 环境类型(
SERVLET
、REACTIVE
、NONE
)。
// WebApplicationType 源码
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;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
设计模式:
- 工厂模式:
WebApplicationType.deduceFromClasspath()
根据类路径中的内容推断 Web 应用的类型。 - 策略模式:不同的
WebApplicationType
会决定使用不同的上下文类型(AnnotationConfigServletWebServerApplicationContext
、ReactiveWebServerApplicationContext
等)。
面试考点:
- 如何通过
META-INF/spring.factories
扩展 Spring Boot 启动行为? - 如何自定义
ApplicationContextInitializer
和ApplicationListener
? WebApplicationType
是如何推断的?Spring Boot 是否支持其他 Web 容器?
3. 环境准备
在 run()
方法中,环境准备阶段的目标是为 Spring 应用上下文提供配置和上下文信息:
- 创建并配置
ConfigurableEnvironment
环境对象。 - 加载系统环境变量、JVM 系统属性、命令行参数等,并将它们存储在
PropertySources
中。 - 执行
ApplicationContextInitializer
并发布环境准备完成事件。
源码分析:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
return environment;
}
- getOrCreateEnvironment:根据应用类型(
WebApplicationType
)创建或获取一个ConfigurableEnvironment
实例。 - configureEnvironment:加载系统属性、环境变量和命令行参数,并将这些参数存储到
PropertySources
中。 - environmentPrepared:通知所有
SpringApplicationRunListeners
环境已经准备就绪。
// getOrCreateEnvironment 源码
protected ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
设计模式:
- 观察者模式:环境准备过程中,通过
SpringApplicationRunListeners
发布事件,所有ApplicationListener
监听并处理这些事件。
面试考点:
- Spring Boot 的环境配置加载顺序是怎样的?
- 如何在启动时传递自定义环境变量?
- 如何通过
EnvironmentPostProcessor
修改环境配置?
4. 容器创建
容器创建是 Spring Boot 启动过程的核心环节,它涉及到 Spring 应用上下文的初始化和配置:
- 通过
createApplicationContext
创建合适的ApplicationContext
实例,默认是AnnotationConfigServletWebServerApplicationContext
。 - 加载并注册核心 Bean 工厂、配置类处理器、自动装配处理器等组件。
- 执行
ApplicationContextInitializer
进行上下文的初步配置。
源码分析:
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 create a default ApplicationContext, " +
"please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
- DEFAULT_SERVLET_WEB_CONTEXT_CLASS:默认是
AnnotationConfigServletWebServerApplicationContext
,用于传统的 Servlet Web 应用。 - createApplicationContext:根据应用类型创建适合的
ApplicationContext
实例,并实例化该类。
// AnnotationConfigServletWebServerApplicationContext 源码
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext {
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
}
设计模式:
- 模板方法模式:定义了容器创建的模板方法,并允许子类进行部分定制。
- 单例模式:
ApplicationContext
是典型的单例模式实例,确保整个应用只有一个上下文实例。
面试考点:
ApplicationContext
的生命周期是怎样的?- 如何自定义 Spring Boot 的上下文类型?
ApplicationContextInitializer
的使用场景有哪些?
5. 填充容器
容器创建后,Spring Boot
会自动装配应用中定义的所有 Bean,过程包括:
- 加载所有 Bean 定义并实例化。
- 执行 Bean 的生命周期回调方法,如
@PostConstruct
、@PreDestroy
。 - 启动内嵌的 Web 服务器(如 Tomcat、Jetty)。
源码分析:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. Prepare this context for refreshing.
prepareRefresh();
// 2. Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// 4. Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 5. Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// 6. Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// 7. Initialize message source for this context.
initMessageSource();
// 8. Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 9. Initialize other special beans in specific context subclasses.
onRefresh();
// 10. Check for listener beans and register them.
registerListeners();
// 11. Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 12. Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}
步骤解析:
-
prepareRefresh():准备刷新上下文,设置启动时间,初始化占位符属性源等。
protected void prepareRefresh() { // Switch to active. this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); // Initialize any placeholder property sources in the context environment. initPropertySources(); // Validate that all properties marked as required are resolvable. getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents. this.earlyApplicationEvents = new LinkedHashSet<>(); }
-
obtainFreshBeanFactory():刷新 Bean 工厂,销毁旧的 Bean 实例并加载新的 Bean 定义。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); }
-
prepareBeanFactory():为 Bean 工厂配置类加载器、注册默认环境信息等。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); // Register environment beans. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as @Autowired dependencies. beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor()); // Register default environment beans. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
-
postProcessBeanFactory():允许在 Bean 工厂标准初始化后进一步自定义 Bean 工厂的设置(通常由子类实现)。
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // For subclasses: do nothing by default. }
-
invokeBeanFactoryPostProcessors():调用所有注册的
BeanFactoryPostProcessor
,包括ConfigurationClassPostProcessor
,该处理器负责解析@Configuration
类并注册相应的 Bean 定义。protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); }
-
registerBeanPostProcessors():注册
BeanPostProcessor
,这些处理器会在每个 Bean 实例化前后进行拦截处理。protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); }
-
initMessageSource():初始化消息源,支持国际化。
protected void initMessageSource() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) { HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource; if (hms.getParentMessageSource() == null) { hms.setParentMessageSource(getInternalParentMessageSource()); } } if (logger.isDebugEnabled()) { logger.debug("Using MessageSource [" + this.messageSource + "]"); } } else { // Use empty MessageSource to be able to accept getMessage calls. DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource = dms; beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); if (logger.isDebugEnabled()) { logger.debug("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); } } }
-
initApplicationEventMulticaster():初始化事件广播器,用于在容器内分发事件。
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isDebugEnabled()) { logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isDebugEnabled()) { logger.debug("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using [" + this.applicationEventMulticaster + "]"); } } }
-
onRefresh():在特定的子类上下文中执行特定的刷新操作,默认实现为空,通常在 Web 应用中用于启动 Web 服务器。
protected void onRefresh() throws BeansException { // For subclasses: do nothing by default. }
-
registerListeners():注册事件监听器,并将他们绑定到事件广播器上。
protected void registerListeners() { for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
-
finishBeanFactoryInitialization():完成 BeanFactory 的初始化工作,包括实例化所有的非懒加载的单例 Bean。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)
&& beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor has registered any.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
- finishRefresh():完成刷新,初始化生命周期管理相关的
LifecycleProcessor
,并发布容器刷新事件,标志着 Spring 应用上下文的启动完成。protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. if (!this.liveBeansViewRegistrations.isEmpty()) { for (String liveBeansViewRegistration : this.liveBeansViewRegistrations) { LiveBeansView.registerApplicationContext(this, liveBeansViewRegistration); } } }
设计模式:
- 责任链模式:在
Bean
的生命周期管理过程中,不同的BeanPostProcessor
通过责任链模式处理Bean
的初始化、依赖注入、后处理等环节。 - 模板方法模式:Spring 在
refresh()
方法中定义了整个容器初始化的流程,并允许子类在特定步骤中提供自己的实现。
面试考点:
Bean
的加载过程及生命周期是怎样的?- 如何自定义
BeanPostProcessor
进行特殊的初始化或销毁操作? - 如何理解 Spring 的事件机制,如何发布自定义事件?
总结
通过对 Spring Boot 启动过程的详细解析,我们不仅可以深入理解 Spring Boot 的工作原理,还能学习到各种设计模式的实际应用。在面试中,Spring Boot 的启动原理是常见的考察点,掌握这些内容能够帮助我们更好地应对面试,并在实际开发中灵活运用。