SpringApplication 类是 Spring Boot 应用程序的核心类之一,负责启动和初始化整个 Spring Boot 应用。通过调用 SpringApplication.run() 方法,Spring Boot 会启动嵌入式的 Web 服务器(如 Tomcat)并创建 Spring 容器。SpringApplication 类具有一系列方法和配置项,允许开发者自定义应用的启动过程。
构造方法:
1. SpringApplication(Class<?>… primarySources)
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
解析:
作用:这是 Spring Boot 启动类的构造函数,用于初始化 SpringApplication 实例。primarySources
参数指定了 Spring 应用的主要配置类(通常是一个带有 @SpringBootApplication 注解的类)。这些配置类将用来初始化
Spring 应用上下文(ApplicationContext)。 默认行为:此构造函数调用了另一个构造函数,传入了
null(表示没有自定义的资源加载器),并传入 primarySources,即传入应用的主配置类。
2. SpringApplication(ResourceLoader resourceLoader, Class<?>… primarySources)
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();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
解析:
作用:
这个构造函数允许开发者传入一个自定义的resourceLoader,用于加载资源文件,并指定应用的主配置类(primarySources)。关键点:
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)):
将 primarySources转换为一个不重复的 LinkedHashSet,确保应用的主配置类是唯一的。this.webApplicationType = WebApplicationType.deduceFromClasspath():
根据类路径中的依赖,自动推断应用的 Web 类型(如SERVLET、REACTIVE)
setInitializers() 和 setListeners():这些方法会加载 Spring工厂实例,用于初始化和监听 Spring 应用的生命周期。
deduceMainApplicationClass():通过检查调用栈,推断出应用的主类(通常是带有@SpringBootApplication 注解的类)。
3. ConfigurableApplicationContext run(String… args)
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
listeners.started(context);
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
解析:
作用:
run() 方法是 Spring Boot 应用的入口,启动 Spring 应用上下文并执行一系列初始化操作。 关键点:
SpringApplicationRunListeners listeners = getRunListeners(args):获取应用启动监听器,并开始执行 starting()。
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments):创建并配置环境,准备环境参数(如配置文件和命令行参数)。
Banner printedBanner = printBanner(environment):如果启用了 banner 模式(即 spring.banner.enabled 配置为 true),则打印 Banner。
context = createApplicationContext():创建 ApplicationContext,即 Spring 容器。
prepareContext():进行应用上下文的进一步准备,包括注册必要的 Bean、设置环境等。
refreshContext():刷新应用上下文,加载所有 Bean。
afterRefresh():完成刷新后的一些处理。
listeners.started(context):通知应用启动完成。
callRunners():调用所有的ApplicationRunner 或 CommandLineRunner 实例。
最后,run() 方法返回创建的ConfigurableApplicationContext,即 Spring 应用上下文。
4. prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments)
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
return environment;
}
解析:
作用:
准备并配置 Spring 应用的环境(如系统属性、环境变量、配置文件等)。
关键点:
ConfigurableEnvironment environment = getOrCreateEnvironment():获取或创建一个新的环境。
configureEnvironment(environment, applicationArguments.getSourceArgs()):配置环境,设置属性源和激活的 profile。
ConfigurationPropertySources.attach(environment):将所有配置属性源(如 application.properties)附加到环境中。
bindToSpringApplication(environment):将环境属性绑定到 SpringApplication 实例。
5. createApplicationContext()
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
} catch (ClassNotFoundException ex) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
解析:
作用:
根据 Web 类型(如 SERVLET 或 REACTIVE),动态选择并创建适当的 ApplicationContext 类型。
关键点:
this.webApplicationType:根据 Web 类型推断是使用 Servlet 环境(传统的 Spring MVC)还是 Reactive 环境(如 WebFlux)。 根据 Web 类型(SERVLET、REACTIVE 或 NONE),选择合适的 ApplicationContext 类并通过反射创建实例。
6. printBanner(ConfigurableEnvironment environment)
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);
}
解析:
作用:
根据配置的 bannerMode 打印应用的 Banner。Spring Boot 默认提供一个 ASCII 字符的 Banner。
关键点:
this.bannerMode == Banner.Mode.OFF:如果 Banner 模式被关闭,返回 null,即不打印Banner。
SpringApplicationBannerPrinter:负责将 Banner 打印到控制台或日志中,具体取决于配置。
bannerMode == Mode.LOG:如果 Banner 模式为日志,打印到日志中;否则,打印到标准输出(控制台)。
7. prepareContext()
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
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 DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
解析:
作用:
该方法是 run() 方法中的一部分,负责配置和初始化应用上下文(ApplicationContext)。它将环境设置到上下文中,并且进行一系列的初始化工作。
关键点:
context.setEnvironment(environment):将环境对象配置到应用上下文中,使得 Spring容器可以访问应用配置(如 application.properties 或 application.yml 中的属性)。
postProcessApplicationContext(context):如果有任何的后处理器(如自定义的ApplicationContext),这时可以应用。
applyInitializers(context):应用初始化器,通常用来在应用启动时进行一些额外的配置,比如设置某些属性、初始化Bean 等。
listeners.contextPrepared(context):通知启动监听器,表示应用上下文已经准备好了。
logStartupInfo() 和 logStartupProfileInfo():如果配置了日志输出,将记录应用的启动信息,如Spring 配置文件、激活的 Profiles、启动时间等。
beanFactory.registerSingleton(“springApplicationArguments”, applicationArguments):将 ApplicationArguments 注册为单例Bean,应用可以通过依赖注入访问这些命令行参数。 context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()):如果启用了懒加载(lazyInitialization配置为 true),将添加懒加载 Bean 的后处理器。load(context, sources.toArray(new Object[0])):加载应用配置源,将 primarySources(即 @SpringBootApplication 注解的类)加载到上下文中。
8. refreshContext()
private void refreshContext(ConfigurableApplicationContext context) {
refresh((ApplicationContext) context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
解析:
作用:
刷新应用上下文,初始化或重新初始化所有的 Bean,并完成 Spring 容器的启动。
关键点:
refresh((ApplicationContext) context):调用 Spring 的 refresh 方法,实际刷新容器,确保Spring 管理的所有 Bean 被初始化。
context.registerShutdownHook():如果配置了registerShutdownHook(默认为 true),则注册一个钩子方法,在 JVM 关闭时调用context.close(),进行 Spring 容器的关闭操作。
9. afterRefresh()
private void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments applicationArguments) {
callRunners(context, applicationArguments);
}
解析:
作用:
在应用上下文刷新之后调用,此方法主要是调用应用中的所有 ApplicationRunner 和 CommandLineRunner实例。
关键点:
callRunners(context, applicationArguments):Spring Boot 提供的ApplicationRunner 和 CommandLineRunner是用于在应用启动完成后执行的接口。这些接口可以在容器启动后执行一些初始化任务(如启动时的批处理操作等)。
10. callRunners()
private void callRunners(ConfigurableApplicationContext context, ApplicationArguments applicationArguments) {
List<ApplicationRunner> runners = getBeansOfType(context, ApplicationRunner.class);
for (ApplicationRunner runner : runners) {
runner.run(applicationArguments);
}
List<CommandLineRunner> commandLineRunners = getBeansOfType(context, CommandLineRunner.class);
for (CommandLineRunner commandLineRunner : commandLineRunners) {
commandLineRunner.run(applicationArguments.getSourceArgs());
}
}
解析:
作用:
调用所有实现了 ApplicationRunner 和 CommandLineRunner 接口的 Beans。在 SpringBoot 启动完成后,这些 Beans 会被调用执行。
关键点:
getBeansOfType(context, ApplicationRunner.class):从 Spring 容器中获取所有 ApplicationRunner 类型的 Beans。
runner.run(applicationArguments):调用每个 ApplicationRunner 实例的 run()方法。ApplicationArguments 提供了命令行参数等信息。
getBeansOfType(context, CommandLineRunner.class):获取所有 CommandLineRunner 类型的Beans。CommandLineRunner 是另外一种 Spring Boot 提供的启动回调接口。
11. getRunListeners()
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
解析:
作用:
获取启动监听器(SpringApplicationRunListener)的实例,这些监听器会在 Spring Boot应用的各个生命周期阶段提供回调。
关键点:
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args):从 META-INF/spring.factories 中加载所有类型为 SpringApplicationRunListener 的实例。
12. getSpringFactoriesInstances()
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
解析:
作用:
加载 SpringFactories 文件中声明的所有实例。这些实例通常是一些工厂类或 Spring组件,用于提供扩展点或插件式的功能。
关键点:
SpringFactoriesLoader.loadFactoryNames(type, classLoader):从 META-INF/spring.factories 文件中加载指定类型的所有实现类。
AnnotationAwareOrderComparator.sort(instances):对加载的实例进行排序,以确保优先级(@Order注解)生效。
总结
标签:SpringBoot,Spring,SpringApplication,environment,第二天,applicationArguments,context From: https://blog.csdn.net/qq_40759033/article/details/143803125SpringApplication 类的核心任务是启动 Spring Boot 应用,并对其生命周期进行管理。以下是该类的主要步骤:
初始化和配置环境:通过构造函数、环境配置、监听器和初始化器来设置应用的环境。 创建和准备上下文:根据 Web 类型(Servlet 或Reactive)创建 ApplicationContext,并将所有必要的配置源(如 primarySources)加载到上下文中。
启动和刷新应用上下文:通过调用 refreshContext() 和相关生命周期方法来启动和刷新 Spring 容器。
运行应用回调:启动时,执行实现 ApplicationRunner 或 CommandLineRunner接口的回调方法,通常用于初始化任务。 生命周期监听:通过 SpringApplicationRunListener 启动监听器来监控应用的启动过程。