欢迎光临
我们一直在努力

【SpringBoot 从入门到架构师】第20章:SpringBoot核心源码解析

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 启动过程通过事件通知扩展点:

  • ApplicationStartingEvent :刚启动时
  • ApplicationEnvironmentPreparedEvent :环境准备完成
  • ApplicationContextInitializedEvent :ApplicationContext 初始化完成
  • ApplicationPreparedEvent :Bean 定义加载完成
  • ApplicationStartedEvent :容器刷新完成
  • ApplicationReadyEvent :Runner 执行完成

  • 五、总结流程图

    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));
    }
    }

    八、自动装配优化建议

  • 使用 @Conditional 精确控制条件
  • 合理使用 @AutoConfigureOrder 和 @AutoConfigureAfter/Before
  • 避免循环依赖
  • 使用 spring-autoconfigure-metadata.properties 提高启动速度
  • 合理分组相关配置
  • 九、常见问题排查

    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()​​

    关键步骤:

  • 配置类解析
  • ​​ConfigurationClassPostProcessor​​ 扫描 @SpringBootApplication 标注的类
  • 递归解析 @ComponentScan、@Import、@Bean 等注解
  • 生成 BeanDefinition 并注册到 BeanDefinitionRegistry
  • Bean定义注册
  • // 示例:ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()
    // 将@Bean方法解析为BeanDefinition
    BeanDefinition beanDefinition = new ConfigurationClassBeanDefinition();
    registry.registerBeanDefinition(beanName, beanDefinition);

    阶段2:Bean实例化(Instantiation)

    入口: ​​AbstractApplicationContext.finishBeanFactoryInitialization()​​ → ​​DefaultListableBeanFactory.preInstantiateSingletons()​​

    关键流程:

  • 获取Bean定义
  • // 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;
    }

    初始化方法调用顺序:

  • ​​@PostConstruct​​ 标注的方法
  • ​​InitializingBean.afterPropertiesSet()​​
  • XML中配置的 init-method 或 @Bean(initMethod)

  • 阶段5:注册完成
    • 单例Bean存入 DefaultSingletonBeanRegistry.singletonObjects Map
    • 后续 getBean() 直接从缓存获取

    三、关键扩展点(BeanPostProcessor 顺序)

    Spring Boot 中重要的 ​​BeanPostProcessor​​ 及其作用:

    表格 还在加载中,请等待加载完成后再尝试复制


    四、Spring Boot 的特殊处理

  • 自动配置类加载: SpringFactoriesLoader.loadFactoryNames() 加载 META-INF/spring.factories 中的 EnableAutoConfiguration 类
  • 条件注解校验: OnBeanCondition、OnClassCondition 等在 ConfigurationClassPostProcessor 阶段过滤Bean定义
  • Bean懒加载: @Lazy 注解的Bean在第一次 getBean() 时才触发上述流程

  • 五、流程图解

    启动SpringApplication
    ↓
    创建AnnotationConfigApplicationContext
    ↓
    refresh()
    ├── invokeBeanFactoryPostProcessors() // 1.加载Bean定义
    ├── registerBeanPostProcessors() // 注册Bean后处理器
    └── finishBeanFactoryInitialization() // 2.实例化单例Bean
    ↓
    DefaultListableBeanFactory.preInstantiateSingletons()
    ↓
    getBean() → doGetBean()
    ├── createBean()
    │ ├── instantiateBean() // 3.实例化(构造器)
    │ ├── populateBean() // 4.依赖注入
    │ └── initializeBean() // 5.初始化
    └── addSingleton() // 6.放入单例池

    六、调试建议

  • 在 AbstractApplicationContext.refresh() 方法打条件断点
  • 重点关注 BeanPostProcessor 接口的实现类
  • 使用 BeanFactory.getBeanDefinitionNames() 查看Bean定义加载阶段结果
  • 通过理解此流程,可以更好地掌握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>

    六、总结要点

  • 自动装配 :通过 spring-boot-starter-web 触发 Tomcat 自动配置
  • 工厂模式 :ServletWebServerFactory 负责创建具体的 WebServer
  • 生命周期管理 :Spring 容器管理 Tomcat 的启动和关闭
  • 配置外部化 :所有配置通过 application.properties/yml 管理
  • 无缝集成 :Servlet API 与 Spring MVC 完美整合
  • 这种设计使得开发者无需关心 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 配置加载的核心原则
  • Profile 机制 :通过 profile 实现环境隔离
  • PropertySource 链 :所有配置源形成一个链,按顺序查找
  • 外部化配置 :支持从多种外部源加载配置
  • 灵活的扩展机制 :可以通过 EnvironmentPostProcessor 自定义加载逻辑
  • 这个机制的设计使得 Spring Boot 能够灵活地支持多种配置源,同时保持清晰的优先级规则。

    赞(0)
    未经允许不得转载:171主机测评 » 【SpringBoot 从入门到架构师】第20章:SpringBoot核心源码解析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址