1. 项目启动流程源码剖析(run方法核心流程)
Spring Boot 项目的启动流程核心在 SpringApplication.run() 方法中。以下是 Spring Boot 2.x/3.x 启动流程的源码剖析(以 2.7.x 为例,3.x 整体流程类似):
一、启动入口
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
二、SpringApplication.run() 核心流程
静态 run 方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String… args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
构造 SpringApplication 实例
public SpringApplication(Class<?>… primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>… primarySources) {
this.resourceLoader = resourceLoader;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 关键步骤:
this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 推断应用类型
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 加载 ApplicationContextInitializer
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 加载 ApplicationListener
this.mainApplicationClass = deduceMainApplicationClass(); // 推断主类
}
关键点 :
- 推断 Web 应用类型 :通过类路径判断是 SERVLET(Spring MVC)、REACTIVE(WebFlux)还是 NONE(非 Web)。
- 加载 SPI 扩展 :通过 spring.factories 加载 ApplicationContextInitializer、ApplicationListener。
3. run() 方法核心流程
public ConfigurableApplicationContext run(String… args) {
// 1. 创建启动计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2. 创建引导上下文(BootstrapContext)和启动上下文(DefaultBootstrapContext)
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 3. 配置 Headless 模式
configureHeadlessProperty();
// 4. 获取 SpringApplicationRunListeners(通过 SPI 加载)
SpringApplicationRunListeners listeners = getRunListeners(args);
// 5. 发布 ApplicationStartingEvent 事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 6. 准备环境(包括命令行参数、配置文件等)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 7. 打印 Banner
Banner printedBanner = printBanner(environment);
// 8. 创建 ApplicationContext(根据 webApplicationType 创建对应类型)
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 9. 准备上下文(核心配置阶段)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 10. 刷新上下文(Spring 容器核心初始化)
refreshContext(context);
// 11. 刷新后置处理(空方法,留给子类扩展)
afterRefresh(context, applicationArguments);
// 12. 停止计时器
stopWatch.stop();
// 13. 发布 ApplicationStartedEvent 事件
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
// 14. 调用 ApplicationRunner 和 CommandLineRunner
callRunners(context, applicationArguments);
// 15. 发布 ApplicationReadyEvent 事件
listeners.ready(context);
} catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
return context;
}
三、关键步骤详解
1. 准备环境(prepareEnvironment)
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 创建环境(根据 WebApplicationType 创建 StandardServletEnvironment/StandardReactiveWebEnvironment/StandardEnvironment)
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境:命令行参数、配置文件(application.yml/properties)、Profiles 等
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布 ApplicationEnvironmentPreparedEvent 事件(此时配置中心客户端可介入)
listeners.environmentPrepared(bootstrapContext, environment);
// 将环境绑定到 SpringApplication
bindToSpringApplication(environment);
// 如果不是自定义环境,进行环境转换(如将 PropertySource 重新排序)
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
// 配置 PropertySource 顺序(确保命令行参数优先级最高)
ConfigurationPropertySources.attach(environment);
return environment;
}
2. 创建 ApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
- SERVLET → AnnotationConfigServletWebServerApplicationContext
- REACTIVE → AnnotationConfigReactiveWebServerApplicationContext
- NONE → AnnotationConfigApplicationContext
3. 准备上下文(prepareContext)
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置环境
context.setEnvironment(environment);
// 后置处理上下文(设置资源加载器、类型转换器等)
postProcessApplicationContext(context);
// 应用所有 ApplicationContextInitializer
applyInitializers(context);
// 发布 ApplicationContextInitializedEvent 事件
listeners.contextPrepared(context);
// 关闭引导上下文
bootstrapContext.close(context);
// 打印启动日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册单例:ApplicationArguments、Banner
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 设置是否允许 BeanDefinition 覆盖
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 设置是否允许循环依赖(默认 true)
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
// 添加 BeanFactory 后置处理器:PropertySourcesPlaceholderConfigurer
addBeanFactoryPostProcessors(beanFactory);
// 加载主类(被 @SpringBootApplication 注解的类)作为 Bean 定义
Set<Object> sources = getAllSources();
load(context, sources.toArray(new Object[0]));
// 发布 ApplicationPreparedEvent 事件
listeners.contextLoaded(context);
}
4. 刷新上下文(refreshContext)
private void refreshContext(ConfigurableApplicationContext context) {
// 实际调用 AbstractApplicationContext.refresh()
refresh(context);
// 注册 ShutdownHook
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException ex) {
// 忽略
}
}
}
AbstractApplicationContext.refresh() 是 Spring 容器的核心初始化流程 :
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新(设置启动时间、状态等)
prepareRefresh();
// 2. 获取新的 BeanFactory(销毁旧的 BeanFactory 并创建新的)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 配置 BeanFactory(设置类加载器、SPEL 解析器等)
prepareBeanFactory(beanFactory);
try {
// 4. 后置处理 BeanFactory(留给子类扩展,如添加 BeanPostProcessor)
postProcessBeanFactory(beanFactory);
// 5. 调用 BeanFactoryPostProcessor(包括 ConfigurationClassPostProcessor 用于解析 @Configuration)
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 7. 初始化 MessageSource(国际化)
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 初始化特殊 Bean(留给子类扩展,如 Spring Boot 的嵌入式 Servlet 容器)
onRefresh();
// 10. 注册监听器
registerListeners();
// 11. 完成 BeanFactory 初始化(初始化所有非懒加载单例 Bean)
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新(发布 ContextRefreshedEvent 事件)
finishRefresh();
} catch (BeansException ex) {
// 销毁已创建的 Bean
destroyBeans();
// 重置 active 标志
cancelRefresh(ex);
throw ex;
}
}
}
Spring Boot 的关键扩展 :
- onRefresh() :在 ServletWebServerApplicationContext 中会创建嵌入式 Tomcat/Jetty/Undertow。
- ConfigurationClassPostProcessor :解析 @Configuration、@ComponentScan、@Import、@Bean 等注解。
5. 调用 Runner
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
// 获取所有 ApplicationRunner 和 CommandLineRunner
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 按 @Order 排序
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
((ApplicationRunner) runner).run(args);
} else if (runner instanceof CommandLineRunner) {
((CommandLineRunner) runner).run(args.getSourceArgs());
}
}
}
四、事件驱动模型
Spring Boot 启动过程通过事件通知扩展点:
五、总结流程图
SpringApplication.run()
├─ 创建 BootstrapContext
├─ 发布 ApplicationStartingEvent
├─ 准备 Environment(加载配置)
├─ 发布 ApplicationEnvironmentPreparedEvent
├─ 创建 ApplicationContext
├─ 准备 Context(加载 Bean 定义)
├─ 发布 ApplicationPreparedEvent
├─ refreshContext() // Spring 容器核心初始化
│ ├─ invokeBeanFactoryPostProcessors() // 解析 @Configuration
│ ├─ onRefresh() // 创建嵌入式 Web 容器(如果是 Web 应用)
│ └─ finishBeanFactoryInitialization() // 初始化单例 Bean
├─ 发布 ApplicationStartedEvent
├─ 调用 ApplicationRunner/CommandLineRunner
└─ 发布 ApplicationReadyEvent
通过这个流程,Spring Boot 完成了从启动到完全可用的整个过程,其中大量使用了事件驱动 和SPI扩展机制 ,提供了丰富的扩展点。
2. 自动装配源码完整链路解析
一、自动装配核心概念
1.1 什么是自动装配
Spring Boot 自动装配是通过约定大于配置的方式,根据类路径下的依赖自动配置 Spring Bean 的过程。
1.2 核心注解
@SpringBootApplication
├── @SpringBootConfiguration
├── @ComponentScan
└── @EnableAutoConfiguration // 自动装配的核心注解
二、自动装配源码完整链路
2.1 启动入口:SpringApplication.run()
// 1. 创建 SpringApplication 实例
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();
}
2.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 {};
}
2.3 AutoConfigurationImportSelector 核心流程
2.3.1 selectImports() 方法
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 1. 获取自动配置元数据
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
2.3.2 getAutoConfigurationEntry() 方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取注解属性(排除的类)
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 关键:获取候选配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 移除重复项
configurations = removeDuplicates(configurations);
// 获取排除的类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查排除的类是否合法
checkExcludedClasses(configurations, exclusions);
// 移除排除的类
configurations.removeAll(exclusions);
// 应用过滤器
configurations = getConfigurationClassFilter().filter(configurations);
// 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
2.3.3 getCandidateConfigurations() 方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 关键:从 META-INF/spring.factories 加载配置
List<String> 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;
}
2.4 SpringFactoriesLoader 加载机制
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
// 从所有 META-INF/spring.factories 文件中加载
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
// 加载所有 META-INF/spring.factories 文件
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// 排序并放入缓存
result.replaceAll((factoryType, implementations) -> implementations.stream()
.sorted(AnnotationAwareOrderComparator.INSTANCE)
.collect(Collectors.toCollection(ArrayList::new)));
cache.put(classLoader, result);
} catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
2.5 自动配置类示例:DataSourceAutoConfiguration
@Configuration(proxyBeanMethods = false) // 配置类
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) // 类路径条件
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory") // Bean不存在条件
@EnableConfigurationProperties(DataSourceProperties.class) // 属性绑定
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {
}
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class,
DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class,
DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}
}
三、条件注解机制
3.1 核心条件注解
// 类路径条件
@ConditionalOnClass
@ConditionalOnMissingClass
// Bean条件
@ConditionalOnBean
@ConditionalOnMissingBean
// 属性条件
@ConditionalOnProperty
// 资源条件
@ConditionalOnResource
// Web应用条件
@ConditionalOnWebApplication
@ConditionalOnNotWebApplication
// 表达式条件
@ConditionalOnExpression
3.2 条件注解执行流程
// ConfigurationClassParser 解析配置类
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) {
// 检查条件注解
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(),
ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 解析配置类
// …
}
四、自动装配优化机制
4.1 spring-autoconfigure-metadata.properties
# 自动配置元数据,用于提前过滤
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration=
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.ConditionalOnClass=org.springframework.data.redis.core.RedisOperations
4.2 AutoConfigurationImportFilter 机制
public interface AutoConfigurationImportFilter {
boolean[] match(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata);
}
五、自动装配完整时序图
启动流程时序图:
1. SpringApplication.run()
│
2. 创建 AnnotationConfigApplicationContext
│
3. 执行 refresh() 方法
│
4. invokeBeanFactoryPostProcessors()
│
5. ConfigurationClassPostProcessor 处理配置类
│
6. 解析 @EnableAutoConfiguration
│
7. AutoConfigurationImportSelector.selectImports()
│
8. 加载 META-INF/spring.factories
│
9. 获取所有自动配置类
│
10. 应用条件注解过滤
│
11. 应用 AutoConfigurationImportFilter
│
12. 注册筛选后的配置类
│
13. 实例化配置类中的 Bean
六、自定义自动配置示例
6.1 创建自动配置类
@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
}
6.2 注册到 spring.factories
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
com.example.MyAutoConfiguration
6.3 创建配置属性类
@ConfigurationProperties("my.service")
public class MyProperties {
private String name = "default";
private int timeout = 1000;
// getters and setters
}
七、调试和诊断技巧
7.1 开启自动配置报告
# application.yml
debug: true # 打印自动配置报告
7.2 查看生效的自动配置
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setBannerMode(Banner.Mode.OFF);
ConfigurableApplicationContext context = app.run(args);
// 查看所有自动配置类
Map<String, Boolean> report = context.getBean(
AutoConfigurationReport.class).getConditionAndOutcomesBySource();
report.forEach((key, value) -> System.out.println(key + " = " + value));
}
}
八、自动装配优化建议
九、常见问题排查
9.1 自动配置不生效
- 检查依赖是否正确引入
- 检查条件注解是否满足
- 查看 debug 日志输出
9.2 自动配置冲突
- 使用 @ConditionalOnMissingBean 避免重复创建
- 使用 @Primary 指定主 Bean
- 使用 @Order 控制顺序
9.3 启动速度慢
- 减少不必要的自动配置
- 使用 spring.autoconfigure.exclude 排除
- 优化条件注解判断逻辑
总结
Spring Boot 自动装配的核心是通过 @EnableAutoConfiguration 触发,由 AutoConfigurationImportSelector 从 META-INF/spring.factories 加载配置类,再通过条件注解机制进行筛选,最终注册符合条件的 Bean 到 Spring 容器中。整个过程体现了"约定大于配置"的思想,极大简化了 Spring 应用的配置工作。
3. Bean加载、实例化、初始化源码流程
Spring Boot 中 Bean 的生命周期(加载、实例化、初始化)是 Spring Framework IoC 容器的核心机制。以下是基于 Spring Boot 2.x / Spring Framework 5.x 的源码流程分析:
一、总体流程概览
Bean定义加载 → Bean实例化 → 依赖注入 → 初始化 → 放入单例池
Spring Boot 通过 SpringApplication.run() 启动,最终委托 AbstractApplicationContext.refresh() 完成容器刷新。
二、详细源码流程
阶段1:Bean定义加载(Bean Definition Loading)
入口: AbstractApplicationContext.refresh() → invokeBeanFactoryPostProcessors()
关键步骤:
// 示例:ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()
// 将@Bean方法解析为BeanDefinition
BeanDefinition beanDefinition = new ConfigurationClassBeanDefinition();
registry.registerBeanDefinition(beanName, beanDefinition);
阶段2:Bean实例化(Instantiation)
入口: AbstractApplicationContext.finishBeanFactoryInitialization() → DefaultListableBeanFactory.preInstantiateSingletons()
关键流程:
// DefaultListableBeanFactory
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (bd.isSingleton() && !bd.isAbstract()) {
getBean(beanName); // 触发实例化
}
}
创建Bean实例
- 入口: AbstractBeanFactory.doGetBean() → createBean()
- 实例化策略: SimpleInstantiationStrategy.instantiate()
- 使用构造器反射 (BeanUtils.instantiateClass())
- 或 CGLIB动态代理 (存在方法拦截时)
// AbstractAutowireCapableBeanFactory.createBeanInstance()
protected BeanWrapper createBeanInstance(String beanName,
RootBeanDefinition mbd,
Object[] args) {
// 1. 工厂方法实例化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 2. 构造器自动注入(@Autowired构造器)
if (autowireNeeded) {
return autowireConstructor(beanName, mbd, null, null);
}
// 3. 默认无参构造器
return instantiateBean(beanName, mbd);
}
阶段3:依赖注入(Dependency Injection)
在 populateBean() 方法中完成:
// AbstractAutowireCapableBeanFactory
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// 1. 处理 @Autowired 注解(AutowiredAnnotationBeanPostProcessor)
// 2. 处理 @Resource 注解(CommonAnnotationBeanPostProcessor)
// 3. 处理 @Value 注解
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 执行后处理器的 postProcessProperties()
// 注入字段和方法
}
}
}
阶段4:初始化(Initialization)
入口: initializeBean()
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// 1. Aware接口回调(BeanNameAware、BeanFactoryAware等)
invokeAwareMethods(beanName, bean);
// 2. BeanPostProcessor前置处理
// @PostConstruct 注解在此阶段通过 CommonAnnotationBeanPostProcessor 执行
wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 3. 调用初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
// 4. BeanPostProcessor后置处理
// AOP代理在此阶段通过 AnnotationAwareAspectJAutoProxyCreator 创建
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
初始化方法调用顺序:
阶段5:注册完成
- 单例Bean存入 DefaultSingletonBeanRegistry.singletonObjects Map
- 后续 getBean() 直接从缓存获取
三、关键扩展点(BeanPostProcessor 顺序)
Spring Boot 中重要的 BeanPostProcessor 及其作用:
表格 还在加载中,请等待加载完成后再尝试复制
四、Spring Boot 的特殊处理
五、流程图解
启动SpringApplication
↓
创建AnnotationConfigApplicationContext
↓
refresh()
├── invokeBeanFactoryPostProcessors() // 1.加载Bean定义
├── registerBeanPostProcessors() // 注册Bean后处理器
└── finishBeanFactoryInitialization() // 2.实例化单例Bean
↓
DefaultListableBeanFactory.preInstantiateSingletons()
↓
getBean() → doGetBean()
├── createBean()
│ ├── instantiateBean() // 3.实例化(构造器)
│ ├── populateBean() // 4.依赖注入
│ └── initializeBean() // 5.初始化
└── addSingleton() // 6.放入单例池
六、调试建议
通过理解此流程,可以更好地掌握Spring Boot的扩展机制(如自定义BeanPostProcessor)和解决Bean加载相关的问题。
4. 内置Tomcat容器启动原理
Spring Boot 内置 Tomcat 的启动原理是其 "约定优于配置" 理念的核心体现。下面我将从几个层面详细解析其启动机制:
一、整体启动流程概览
SpringApplication.run()
└── SpringApplication.refreshContext()
└── ServletWebServerApplicationContext.refresh()
├── ServletWebServerApplicationContext.onRefresh()
│ └── createWebServer() // 关键:创建Web服务器
└── ServletWebServerApplicationContext.finishRefresh()
└── startWebServer() // 启动Web服务器
二、核心原理详解
1. 自动配置机制
// spring-boot-autoconfigure 中的关键配置类
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class,
search = SearchStrategy.CURRENT)
public class EmbeddedTomcatAutoConfiguration {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
- 当检测到类路径下有 Tomcat.class 时自动配置
- 当没有自定义 ServletWebServerFactory Bean 时生效
2. Web服务器工厂创建
public class TomcatServletWebServerFactory {
@Override
public WebServer getWebServer(ServletContextInitializer… initializers) {
// 1. 创建Tomcat实例
Tomcat tomcat = new Tomcat();
// 2. 配置基础目录
File baseDir = (this.baseDirectory != null) ?
this.baseDirectory : createTempDir("tomcat");
// 3. 配置连接器(默认8080端口)
Connector connector = new Connector(this.protocol);
connector.setPort(getPort());
tomcat.getService().addConnector(connector);
// 4. 配置引擎和Host
Engine engine = tomcat.getEngine();
engine.setDefaultHost(getHostname());
// 5. 配置Context
Context context = tomcat.addContext("", baseDir.getAbsolutePath());
// 6. 应用初始化器
configureContext(context, initializers);
return new TomcatWebServer(tomcat, getPort() >= 0);
}
}
3. Servlet容器初始化
// ServletWebServerApplicationContext 中的关键方法
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) {
// 从工厂获取WebServer
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
initPropertySources();
}
4. 嵌入式Tomcat的启动
public class TomcatWebServer implements WebServer {
private final Tomcat tomcat;
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
this.tomcat = tomcat;
initialize();
if (autoStart) {
start(); // 启动Tomcat
}
}
private void initialize() throws WebServerException {
// 1. 初始化Tomcat
this.tomcat.start();
// 2. 启动守护线程
startDaemonAwaitThread();
}
private void startDaemonAwaitThread() {
Thread awaitThread = new Thread("container-" + (containerCounter.get())) {
@Override
public void run() {
TomcatWebServer.this.tomcat.getServer().await();
}
};
awaitThread.setDaemon(false);
awaitThread.start();
}
}
三、关键特性实现
1. 端口自动配置
# application.yml
server:
port: 8080 # 默认值
tomcat:
max-threads: 200
uri-encoding: UTF-8
2. Servlet、Filter、Listener注册
// 自动注册的三种方式:
// 1. @Bean 方式
@Bean
public ServletRegistrationBean<MyServlet> myServlet() {
return new ServletRegistrationBean<>(new MyServlet(), "/my/*");
}
// 2. 扫描 ServletComponentScan
@ServletComponentScan
public class Application {
// 会自动扫描 @WebServlet、@WebFilter、@WebListener
}
// 3. 实现 ServletContextInitializer
@Bean
public ServletContextInitializer servletContextInitializer() {
return servletContext -> {
// 动态注册
};
}
3. SSL支持
@Configuration
public class SSLConfig {
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addAdditionalTomcatConnectors(createSslConnector());
return factory;
}
private Connector createSslConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
// SSL配置…
return connector;
}
}
四、启动过程时序图

五、自定义配置扩展点
1. 自定义Tomcat配置
@Configuration
public class TomcatConfig {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory>
tomcatCustomizer() {
return factory -> {
factory.setPort(9090);
factory.setContextPath("/api");
factory.addConnectorCustomizers(connector -> {
connector.setProperty("maxThreads", "500");
connector.setProperty("acceptCount", "200");
});
};
}
}
2. 替换为其他容器
<!– 使用Jetty –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!– 使用Undertow –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
六、总结要点
这种设计使得开发者无需关心 Servlet 容器的具体实现细节,只需关注业务逻辑,真正实现了 "开箱即用" 的开发体验。
5. 配置文件加载优先级源码解析
一、配置文件加载的整体流程
1.1 核心入口:SpringApplication.run()
// SpringApplication.java
public ConfigurableApplicationContext run(String… args) {
// …
// 准备环境,这里会加载配置文件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// …
}
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境,这里会加载配置文件
configureEnvironment(environment, applicationArguments.getSourceArgs());
// …
}
1.2 环境配置和配置文件加载
// SpringApplication.java
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
// 添加属性源,包括配置文件
configurePropertySources(environment, args);
// 配置Profiles
configureProfiles(environment, args);
}
二、配置文件加载的核心类
2.1 ConfigFileApplicationListener
这是配置文件加载的核心监听器:
// ConfigFileApplicationListener.java
public class ConfigFileApplicationListener
implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
// 配置文件搜索路径
private static final String DEFAULT_SEARCH_LOCATIONS =
"classpath:/,classpath:/config/,file:./,file:./config/";
// 配置文件名称
private static final String DEFAULT_NAMES = "application";
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
// 添加属性源
addPropertySources(environment, application.getResourceLoader());
}
private void addPropertySources(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
// 获取所有属性源
RandomValuePropertySource.addToEnvironment(environment);
// 加载配置文件
new Loader(environment, resourceLoader).load();
}
}
2.2 Loader 内部类
// ConfigFileApplicationListener.Loader
class Loader {
void load() {
// 获取激活的profiles
FilteredProfiles filteredProfiles = getProfiles();
// 加载默认配置文件(没有profile的)
load("application", null, filteredProfiles, false);
// 加载带profile的配置文件
load("application", filteredProfiles.getActive(), filteredProfiles, false);
// 加载带profile的配置文件,包含外部配置
load("application", filteredProfiles.getActive(), filteredProfiles, true);
}
private void load(String name, Profile profile,
FilteredProfiles filteredProfiles, boolean addToEnvironment) {
// 获取所有配置文件位置
Set<String> processed = new HashSet<>();
for (String location : getSearchLocations()) {
// 加载配置文件
load(location, name, profile, filteredProfiles, addToEnvironment, processed);
}
}
}
三、配置文件加载优先级源码解析
3.1 优先级顺序的确定
// ConfigFileApplicationListener.java
private static final String DEFAULT_SEARCH_LOCATIONS =
"classpath:/,classpath:/config/,file:./,file:./config/";
// 搜索位置的优先级顺序
private Set<String> getSearchLocations() {
// 1. 先检查 spring.config.location 配置
if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
return getSearchLocations(CONFIG_LOCATION_PROPERTY);
}
// 2. 检查 spring.config.additional-location
Set<String> locations = getSearchLocations(CONFIG_ADDITIONAL_LOCATION_PROPERTY);
// 3. 添加默认位置
locations.addAll(asResolvedSet(ConfigFileApplicationListener.this.searchLocations,
DEFAULT_SEARCH_LOCATIONS));
return locations;
}
3.2 实际加载顺序
private void load(Profile profile, DocumentFilter filter,
DocumentConsumer consumer) {
// 按照以下顺序加载:
// 1. 先加载不带profile的
getSearchLocations().forEach((location) -> {
// 加载 application.yml/properties
load(location, null, profile, filter, consumer);
});
// 2. 再加载带profile的
getSearchLocations().forEach((location) -> {
// 加载 application-{profile}.yml/properties
load(location, profile, profile, filter, consumer);
});
}
四、完整的优先级顺序
4.1 位置优先级(从高到低)
// 这是实际的加载顺序
public static final String DEFAULT_SEARCH_LOCATIONS =
"classpath:/,classpath:/config/,file:./,file:./config/";
// 实际优先级:
// 1. file:./config/ (当前目录下的config目录)
// 2. file:./ (当前目录)
// 3. classpath:/config/ (classpath下的config目录)
// 4. classpath:/ (classpath根目录)
4.2 文件类型优先级
// PropertySourceLoader 的实现类
public class YamlPropertySourceLoader implements PropertySourceLoader {
@Override
public String[] getFileExtensions() {
return new String[] { "yml", "yaml" };
}
}
public class PropertiesPropertySourceLoader implements PropertySourceLoader {
@Override
public String[] getFileExtensions() {
return new String[] { "properties", "xml" };
}
}
// 加载时的文件扩展名检查顺序
private String[] getFileExtensions() {
// 实际顺序取决于PropertySourceLoader的注册顺序
// 通常:.properties > .yml > .yaml > .xml
}
五、Profile 的处理机制
5.1 Profile 激活顺序
// ConfigFileApplicationListener.Loader
private void load() {
// 获取所有profile
Profiles profiles = getProfiles(environment);
// 加载顺序:
// 1. 先加载 application.yml (无profile)
// 2. 按profile激活顺序加载 application-{profile}.yml
// 3. 后激活的profile会覆盖先激活的配置
for (Profile profile : profiles.getActive()) {
load("application", profile, profiles, false);
}
}
5.2 Profile 文档处理
// DocumentFilter 用于筛选对应profile的配置
private DocumentFilter getDocumentFilter(Profile profile) {
return (document) -> {
// 检查文档是否匹配profile
String profileProperty = document.getProfiles();
return profile == null || profileProperty == null
|| profile.matches(profileProperty);
};
}
六、属性源合并机制
6.1 PropertySource 的添加
// MutablePropertySources 管理所有PropertySource
public class MutablePropertySources implements PropertySources {
private final List<PropertySource<?>> propertySourceList =
new CopyOnWriteArrayList<>();
public void addLast(PropertySource<?> propertySource) {
// 添加到列表末尾
this.propertySourceList.add(propertySource);
}
public void addFirst(PropertySource<?> propertySource) {
// 添加到列表开头(优先级最高)
this.propertySourceList.add(0, propertySource);
}
}
6.2 属性查找顺序
// PropertySourcesPropertyResolver 负责解析属性
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
@Override
public String getProperty(String key) {
// 按顺序查找,找到第一个就返回
for (PropertySource<?> propertySource : this.propertySources) {
Object value = propertySource.getProperty(key);
if (value != null) {
return value.toString();
}
}
return null;
}
}
七、外部化配置的加载
7.1 命令行参数
// DefaultApplicationArguments
public class DefaultApplicationArguments implements ApplicationArguments {
public DefaultApplicationArguments(String… args) {
// 解析命令行参数
this.args = args;
this.source = new SimpleCommandLinePropertySource(args);
}
}
// 命令行参数的优先级非常高
// 在SpringApplication.run()中:
public ConfigurableApplicationContext run(String… args) {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 命令行参数会作为高优先级PropertySource添加
}
7.2 系统属性和环境变量
// SpringApplication 中环境准备
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 添加命令行参数
environment.getPropertySources().addFirst(
new SimpleCommandLinePropertySource(args));
// 系统属性和环境变量由StandardEnvironment自动添加
// 优先级:命令行参数 > JVM系统属性 > 系统环境变量 > 配置文件
}
八、完整的优先级总结
根据源码分析,完整的优先级顺序如下:
8.1 位置优先级(从高到低)
// 1. 命令行参数 (–spring.config.location=)
// 2. Java系统属性 (System.getProperties())
// 3. 操作系统环境变量
// 4. 当前目录下的 /config 子目录
// 5. 当前目录
// 6. classpath下的 /config 包
// 7. classpath根目录
8.2 文件优先级(同一目录下)
// 1. application-{profile}.properties
// 2. application-{profile}.yml
// 3. application-{profile}.yaml
// 4. application.properties
// 5. application.yml
// 6. application.yaml
九、调试和验证方法
9.1 查看加载的属性源
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private ConfigurableEnvironment environment;
@Override
public void run(String… args) {
System.out.println("=== 加载的属性源 ===");
environment.getPropertySources().forEach(ps -> {
System.out.println(ps.getName() + " : " + ps.getClass().getSimpleName());
});
}
}
9.2 查看具体的加载顺序
// 添加调试日志
@Configuration
public class ConfigDebug implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(
ConfigurableEnvironment environment,
SpringApplication application) {
// 查看所有PropertySource
MutablePropertySources sources = environment.getPropertySources();
sources.stream().forEach(source -> {
System.out.println("Source: " + source.getName());
});
}
}
十、关键设计要点
这个机制的设计使得 Spring Boot 能够灵活地支持多种配置源,同时保持清晰的优先级规则。


