SpringApplication
java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
run
java
public ConfigurableApplicationContext run(String... args) {
Startup startup = Startup.create();
// 默认启用
if (this.properties.isRegisterShutdownHook()) {
SpringApplication.shutdownHook.enableShutdownHookAddition();
}
// 创建 DefaultBootstrapContext,通过 bootstrapRegistryInitializers 列表中的初始化器对其进行配置,确保在应用启动前完成必要的设置
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 配置系统属性 java.awt.headless,决定是否启用无头模式
// 该属性一般用于图形界面应用,默认是启用无头模式(headless),表示不需要图形界面支持
configureHeadlessProperty();
// 获取所有的 SpringApplicationRunListener 实例,并将它们封装成一个 SpringApplicationRunListeners 对象
// 启动监听器用于监听应用启动的各个阶段
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动监听器并通知应用启动开始
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 封装传入的命令行参数 args 为 ApplicationArguments 对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 1. 创建 ApplicationServletEnvironment
// 2. 设置 ApplicationConversionService
// 3. 根据 args 配置 PropertySources,Profiles
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 根据 Banner.Mode 配置决定是否打印 banner,如果是 LOG 模式,则通过 logger 输出,否则输出到控制台(System.out)
Banner printedBanner = printBanner(environment);
// 创建 AnnotationConfigServletWebServerApplicationContext
// GenericApplicationContext -> 创建 DefaultListableBeanFactory
// AbstractApplicationContext -> 创建 PathMatchingResourcePatternResolver
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 1. context 配置 environment
// 2. context.beanFactory 配置 context.ConversionService
// 3. ApplicationContextInitializer.initialize
// 4. 添加特殊的单例bean: springApplicationArguments, springBootBanner,并设置beanFacotory 禁止循环依赖,禁止 Bean 定义覆盖
// 5. 添加工厂处理器PropertySourceOrderingBeanFactoryPostProcessor,加载Sources
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
// // 在刷新完成后,执行一些后处理逻辑,默认空实现
afterRefresh(context, applicationArguments);
startup.started();
if (this.properties.isLogStartupInfo()) {
new StartupInfoLogger(this.mainApplicationClass, environment).logStarted(getApplicationLog(), startup);
}
listeners.started(context, startup.timeTakenToStarted());
// 按顺序执行所有 Runner 类型 Bean,并处理异常
// Runner: CommandLineRunner, ApplicationRunner, JobLauncherApplicationRunner
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;
}
prepareEnvironment
推荐阅读:
- [spring6: PropertySource & PropertyResolver & Environment]-源码分析
- [spring6: ResolvableType & TypeDescriptor & ConversionService]-类型系统
java
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 创建 ApplicationServletEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 设置 ApplicationConversionService,根据 args 配置 PropertySources,Profiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(bootstrapContext, environment);
// 将特定的 PropertySource 移到 PropertySources 列表的末尾
ApplicationInfoPropertySource.moveToEnd(environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");
// 使用 Binder 来绑定 'spring.main' 配置到 'this.properties'
bindToSpringApplication(environment);
// 判断是否需要将一个 ConfigurableEnvironment 实例转换为目标类型的 ConfigurableEnvironment
// 此处已是目标类型,直接返回
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
// deduceEnvironmentClass(): ApplicationServletEnvironment.class
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
java
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
// WebApplicationType.SERVLET
WebApplicationType webApplicationType = this.properties.getWebApplicationType();
ConfigurableEnvironment environment = this.applicationContextFactory.createEnvironment(webApplicationType);
if (environment == null && this.applicationContextFactory != ApplicationContextFactory.DEFAULT) {
environment = ApplicationContextFactory.DEFAULT.createEnvironment(webApplicationType);
}
return (environment != null) ? environment : new ApplicationEnvironment();
}
java
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
environment.setConversionService(new ApplicationConversionService());
}
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
if (!CollectionUtils.isEmpty(this.defaultProperties)) {
DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
}
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains(name)) {
PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name);
composite
.addPropertySource(new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
environment.getPropertySources().addLast(new ApplicationInfoPropertySource(this.mainApplicationClass));
}
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
}
prepareContext
java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
// context.beanFactory 配置 context.ConversionService
postProcessApplicationContext(context);
// 略,未执行
addAotGeneratedInitializerIfNecessary(this.initializers);
// 在 ApplicationContext 刷新前调用所有已配置的 ApplicationContextInitializer 实例
// 使得开发者可以在应用启动时,对 ApplicationContext 进行个性化的初始化配置
applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.properties.isLogStartupInfo()) {
logStartupInfo(context.getParent() == null);
logStartupInfo(context);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
//是否允许 Bean 之间存在循环依赖, 默认为false
// 如果设置为 true,Spring 容器会尝试自动解决循环依赖问题;
// 如果设置为 false,则遇到循环依赖时会抛出异常
autowireCapableBeanFactory.setAllowCircularReferences(this.properties.isAllowCircularReferences());
if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
// 是否允许重写现有的 Bean 定义,默认为false
// 如果设置为 true,则可以注册具有相同名称的 Bean 定义,这样会覆盖先前的定义;
// 如果设置为 false,则不允许覆盖,注册新的 Bean 定义时会抛出异常。
listableBeanFactory.setAllowBeanDefinitionOverriding(this.properties.isAllowBeanDefinitionOverriding());
}
}
// false
if (this.properties.isLazyInitialization()) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// false
if (this.properties.isKeepAlive()) {
context.addApplicationListener(new KeepAlive());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// 当前没有使用 AOT 生成的优化代码,此时进入加载源的流程
if (!AotDetector.useGeneratedArtifacts()) {
// Load the sources
Set<Object> sources = getAllSources();
Assert.state(!ObjectUtils.isEmpty(sources), "No sources defined");
load(context, sources.toArray(new Object[0]));
}
listeners.contextLoaded(context);
}
refreshContext
java
private void refreshContext(ConfigurableApplicationContext context) {
if (this.properties.isRegisterShutdownHook()) {
// 注册 shutdownHook 为 JVM ShutdownHook
// 当 JVM 进程开始终止时,所有注册的 Shutdown Hook 将会按先后顺序执行,实现应用程序优雅关闭
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
java
protected void refresh(ConfigurableApplicationContext applicationContext) {
// ServletWebServerApplicationContext.refresh -> AbstractApplicationContext.refresh
applicationContext.refresh();
}
AbstractApplicationContext.refresh
推荐阅读:[spring6: AbstractApplicationContext.refresh()]-源码分析
java
@Override
public void refresh() throws BeansException, IllegalStateException {
this.startupShutdownLock.lock();
try {
this.startupShutdownThread = Thread.currentThread();
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (RuntimeException | Error ex ) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
contextRefresh.end();
}
}
finally {
this.startupShutdownThread = null;
this.startupShutdownLock.unlock();
}
}
afterRefresh
java
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {}