核心流程
- 启动入口:
SpringApplication.run()
- 创建
SpringApplication
实例,初始化 ApplicationContext
(默认 AnnotationConfigApplicationContext
)。
- 加载
META-INF/spring.factories
中的 ApplicationContextInitializer
和 ApplicationListener
。
- 准备环境(
Environment
)
- 读取默认配置application.yml及命令行参数。
- 配置
Profiles``prod
)。
- 创建并刷新
ApplicationContext
- 调用
AbstractApplicationContext.refresh()
,核心流程:
- Bean 定义加载:扫描
@Component
、@Service
等注解类。
- Bean 实例化:通过
BeanFactory
创建单例 Bean。
- 依赖注入:处理
@Autowired
、@Resource
等注解。
- 初始化回调:执行
@PostConstruct
、InitializingBean.afterPropertiesSet()
。
- 执行
Runner
和事件监听
CommandLineRunner
/ApplicationRunner
:在 refresh()
完成后触发 run()
。
- 发布事件:如
ApplicationReadyEvent
(表示完全启动)。
- 内嵌 Web 服务器启动(如 Tomcat)
- 如果是 Web 应用,自动启动内嵌服务器(通过
ServletWebServerFactory
)。
关键特性
- 自动配置:
@EnableAutoConfiguration
加载 spring-boot-autoconfigure
中的预定义配置。
- 条件装配:
@Conditional
系列注解控制 Bean 的加载(如 @ConditionalOnClass
)。
- 启动优化:延迟初始化(
spring.main.lazy-initialization=true
)。
一、初始化阶段
1. 初始化
实例化SpringApllication对象,完成初始化工作。
1 2 3 4 5 6 7 8 9
| 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); }
|
1.1 构造初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public SpringApplication(Class<?>... primarySources) { this(null, primarySources); }
@SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
|
二、执行run() 方法
执行SpringApplication实例的run方法,默认返回AnnotationConfigServletWebServerApplicationContext
上下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| public ConfigurableApplicationContext run(String... args) { Startup startup = Startup.create(); if (this.registerShutdownHook) { SpringApplication.shutdownHook.enableShutdownHookAddition(); } ** DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); startup.started(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), startup); } listeners.started(context, startup.timeTakenToStarted()); callRunners(context, applicationArguments); } catch (Throwable ex) { throw handleRunFailure(context, ex, listeners); } try { if (context.isRunning()) { listeners.ready(context, startup.ready()); } } catch (Throwable ex) { throw handleRunFailure(context, ex, null); } return context; }
|
2.1 创建启动上下文
创建完启动事件,完成引导上下文的创建
1 2 3 4 5 6 7 8
| private DefaultBootstrapContext createBootstrapContext() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext)); return bootstrapContext; }
|
2.2 监听器列表
创建SpringApplicationRunListeners 对象 , 实现SpringApplicationRunListener
接口,可以用日志配置加载等等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private SpringApplicationRunListeners getRunListeners(String[] args) { ArgumentResolver argumentResolver = ArgumentResolver.of(SpringApplication.class, this); argumentResolver = argumentResolver.and(String[].class, args); List<SpringApplicationRunListener> listeners = getSpringFactoriesInstances(SpringApplicationRunListener.class, argumentResolver); SpringApplicationHook hook = applicationHook.get(); SpringApplicationRunListener hookListener = (hook != null) ? hook.getRunListener(this) : null; if (hookListener != null) { listeners = new ArrayList<>(listeners); listeners.add(hookListener); } return new SpringApplicationRunListeners(logger, listeners, this.applicationStartup); }
|
2.3 封装命令行参数
将传入的命令行参数封装成 ApplicationArguments 对象,便于后续使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class DefaultApplicationArguments implements ApplicationArguments {
private final Source source;
private final String[] args;
public DefaultApplicationArguments(String... args) { Assert.notNull(args, "Args must not be null"); this.source = new Source(args); this.args = args; }
private static class Source extends SimpleCommandLinePropertySource {
Source(String[] args) { super(args); }
}
}
|
2.4 创建并配置环境变量
准备并返回应用的环境配置对象 ConfigurableEnvironment,用于管理配置属性和环境信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties."); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader()); environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
private Class<? extends ConfigurableEnvironment> deduceEnvironmentClass() { Class<? extends ConfigurableEnvironment> environmentType = this.applicationContextFactory.getEnvironmentType(this.webApplicationType); if (environmentType == null && this.applicationContextFactory != ApplicationContextFactory.DEFAULT) { environmentType = ApplicationContextFactory.DEFAULT.getEnvironmentType(this.webApplicationType); } if (environmentType == null) { return ApplicationEnvironment.class; } return environmentType; }
|
2.5 打印Banner
启用时Banner日志输出
1 2 3 4 5 6 7 8 9 10 11
| private Banner printBanner(ConfigurableEnvironment environment) { if (this.bannerMode == Banner.Mode.OFF) { return null; } ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader : new DefaultResourceLoader(null); SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner); if (this.bannerMode == Mode.LOG) { return bannerPrinter.print(environment, this.mainApplicationClass, logger); } return bannerPrinter.print(environment, this.mainApplicationClass, System.out); }
|
2.6 创建应用上下文(根据web应用类型)
创建应用上下文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); }
@Override public ConfigurableApplicationContext create(WebApplicationType webApplicationType) { try { return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create, this::createDefaultApplicationContext); } catch (Exception ex) { throw new IllegalStateException("Unable create a default ApplicationContext instance, " + "you may need a custom ApplicationContextFactory", ex); } }
private ConfigurableApplicationContext createDefaultApplicationContext() { if (!AotDetector.useGeneratedArtifacts()) { return new AnnotationConfigApplicationContext(); } return new GenericApplicationContext(); }
private <T> T getFromSpringFactories(WebApplicationType webApplicationType, BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) { for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class, getClass().getClassLoader())) { T result = action.apply(candidate, webApplicationType); if (result != null) { return result; } } return (defaultResult != null) ? defaultResult.get() : null; }
|
2.7 应用上下文准备
创建完上下文后、为上下文准备环境变量、ApplicationContextInitializer实现的初始化工作、beanFactory注册自定义配置的Bean实例、循环引用、bean覆盖、懒加载设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment);、 this.postProcessApplicationContext(context); this.addAotGeneratedInitializerIfNecessary(this.initializers); this.applyInitializers(context); listeners.contextPrepared(context); bootstrapContext.close(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) { autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences); if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) { listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } if (this.keepAlive) { context.addApplicationListener(new KeepAlive()); } context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context)); if (!AotDetector.useGeneratedArtifacts()) { Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); this.load(context, sources.toArray(new Object[0])); } listeners.contextLoaded(context); }
protected void postProcessApplicationContext(ConfigurableApplicationContext context) { if (this.beanNameGenerator != null) { context.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", this.beanNameGenerator); } if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { GenericApplicationContext genericApplicationContext = (GenericApplicationContext)context; genericApplicationContext.setResourceLoader(this.resourceLoader); }
if (context instanceof DefaultResourceLoader) { DefaultResourceLoader defaultResourceLoader = (DefaultResourceLoader)context; defaultResourceLoader.setClassLoader(this.resourceLoader.getClassLoader()); } } if (this.addConversionService) { context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService()); }
} protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); }
if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); }
if (this.environment != null) { loader.setEnvironment(this.environment); }
loader.load(); }
|
2.8 应用上下文刷新
钩子注册当前上下文,调用上下文刷新方法。
准备阶段:加锁防止并发刷新,记录启动时间,初始化环境变量
创建Bean工厂:加载/刷新Bean定义(通过obtainFreshBeanFactory)
配置工厂:设置类加载器、后处理器等基础配置(prepareBeanFactory)
后处理阶段:执行Bean工厂后处理器和Bean后处理器注册
初始化组件:初始化消息源、事件广播器等特殊组件
完成初始化:实例化所有非懒加载单例Bean,发布上下文刷新事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| private void refreshContext(ConfigurableApplicationContext context) { if (this.properties.isRegisterShutdownHook()) { shutdownHook.registerApplicationContext(context); } refresh(context); }
@Override public void refresh() throws BeansException, IllegalStateException { this.startupShutdownLock.lock(); try { this.startupShutdownThread = Thread.currentThread();
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try { postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); beanPostProcess.end();
initMessageSource();
initApplicationEventMulticaster();
**onRefresh**();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh(); }
catch (RuntimeException | Error ex ) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); }
destroyBeans();
cancelRefresh(ex);
throw ex; }
finally { contextRefresh.end(); } } finally { this.startupShutdownThread = null; this.startupShutdownLock.unlock(); } }
|
2.9 应用上下文刷新后置操作
默认无操作,子类拓展实现
1 2
| protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { }
|
2.10 调用runnner接口
从Spring容器中获取所有Runner类型的Bean(包括ApplicationRunner
和CommandLineRunner
)将这些Runner实例与其对应的Bean名称存入IdentityHashMap创建一个带排序规则的比较器(考虑@Order注解和依赖顺序)按顺序执行所有Runner实例的run方法。
1 2 3 4 5 6 7 8 9 10 11 12 13
| private void callRunners(ConfigurableApplicationContext context, ApplicationArguments args) { ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); String[] beanNames = beanFactory.getBeanNamesForType(Runner.class); Map<Runner, String> instancesToBeanNames = new IdentityHashMap<>(); for (String beanName : beanNames) { instancesToBeanNames.put(beanFactory.getBean(beanName, Runner.class), beanName); } Comparator<Object> comparator = getOrderComparator(beanFactory) .withSourceProvider(new FactoryAwareOrderSourceProvider(beanFactory, instancesToBeanNames)); instancesToBeanNames.keySet().stream().sorted(comparator).forEach((runner) -> callRunner(runner, args)); }
|
三、总结
3.1 题目
3.1.1 在Spring Boot启动时执行特定逻辑,可以通过哪些方式
- 使用
CommandLineRunner
或 ApplicationRunner
- 监听
ApplicationReadyEvent
事件(触发时机晚于Runnner
)
- 使用
@PostConstruct
注解
- 实现
InitializingBean
接口配合@Component