// 运行
SpringApplication.run(SpringApplicationApplication.class, args);
// 自定义
SpringApplication springApplication = new SpringApplication(SpringApplicationApplication.class);
springApplication.setBannerMode(Banner.Mode.CONSOLE);
// 设置运行环境 【NONE:非Web环境,SERVLET:WebServlet,REACTIVE:WebFlux异步】
springApplication.setWebApplicationType(WebApplicationType.NONE);
// 设置配置文件环境
springApplication.setAdditionalProfiles("prod");
// Headless模式是系统的一种配置模式。在系统可能缺少显示设备、键盘或鼠标这些外设的情况下可以使用该模式。
// 在开发图形化界面时可设置为false
springApplication.setHeadless(true);
new SpringApplicationBuilder(SpringApplicationApplication.class)
.bannerMode(Banner.Mode.CONSOLE)
.web(WebApplicationType.NONE)
.profiles("prod")
.headless(true);
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@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();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
Java 配置 Class 或 XML 上下文配置文件集合,用于 Spring Boot BeanDefinitionLoader 读取 ,并且将配置源解析加载为
第一种@SpringBootApplication
注解标注的类,不仅限于本身,eg:
public static void main(String[] args) {
// 运行
SpringApplication.run(ApplicationApplication.class, args);
}
@SpringBootApplication
public static class ApplicationApplication{
}
第二种通过setSources
配置:``,eg:
public static void main(String[] args) {
// 运行
// SpringApplication.run(ApplicationApplication.class, args);
Set<String> sourceSet = new HashSet<>();
sourceSet.add(ApplicationApplication.class.getName());
SpringApplication springApplication = new SpringApplication();
// sources can be:a class name, package name, or an XML resource location.
// 源可以是一个类的名字、包名、本地xml文件路径
springApplication.setSources(sourceSet);
springApplication.run(args);
}
@SpringBootApplication
public static class ApplicationApplication{
}
根据是否存在某个类来判断当前应用类型:WebServlet、WebFlux和普通应用
org.springframework.boot.SpringApplication#SpringApplication
SpringApplication:this.webApplicationType = WebApplicationType.deduceFromClasspath();
org.springframework.boot.WebApplicationType#deduceFromClasspath
方法代如下:
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) // 1
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) { // 2
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET; // 3
}
由以上代码可知:
SERVLET
应用环境,只存在WEBFLUX_INDICATOR_CLASS
时,才为WebApplicationType.REACTIVE
SERVLET_INDICATOR_CLASSES
中类均不存在时,返回return WebApplicationType.NONE
WebApplicationType.SERVLET
利用 Spring 工厂加载机制,实例化 ApplicationContextInitializer 实现类,并排序对象集合。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
实际调用方法:
private Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 通过工厂机制获取实现类名字 SpringFactoriesLoader->META-INF/spring.factories->names
Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 创建实例
List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 根据order排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
通过异常堆栈来判断符合条件(包含main方法)的类
debug
->stackTrace
截图如下private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
核心代码
public ConfigurableApplicationContext run(String... args) {
// 计时器初始化
StopWatch stopWatch = new StopWatch();
// 开始计时
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
// 配置Headless参数
this.configureHeadlessProperty();
// 加载监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 运行监听器
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
核心代码
// 加载监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
// 运行监听器
listeners.starting();
getRunListeners:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
// 通过工厂机制加载SpringApplicationRunListener的实现类,实际即为:org.springframework.boot.context.event.EventPublishingRunListener
// 加载完毕之后,构造SpringApplicationRunListeners组合对象(设计模式),
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
SpringApplicationRunListener 监听多个运行状态方法:
监听方法 | 阶段说明 | Spring Boot 起始版本 |
---|---|---|
starting() | Spring 应用刚启动 | 1.0 |
environmentPrepared(ConfigurableEnvironment) | ConfigurableEnvironment 准备妥当,允许将其调整 | 1.0 |
contextPrepared(ConfigurableApplicationContext) | ConfigurableApplicationContext 准备妥当,允许将其调整 | 1.0 |
contextLoaded(ConfigurableApplicationContext) | ConfigurableApplicationContext 已装载,但仍未启动 | 1.0 |
started(ConfigurableApplicationContext) | ConfigurableApplicationContext 已启动,此时 Spring Bean 已初始化完成 | 2.0 |
running(ConfigurableApplicationContext) | Spring 应用正在运行 | 2.0 |
failed(ConfigurableApplicationContext,Throwable) | Spring 应用运行失败 | 2.0 |
Spring Boot 通过 SpringApplicationRunListener 的实现类 EventPublishingRunListener 利用 Spring Framework 事件API ,广播 Spring Boot 事件。
监听方法 | Spring Boot 事件 | Spring Boot 起始版本 |
---|---|---|
starting() | ApplicationStartingEvent | 1.5 |
environmentPrepared(ConfigurableEnvironment) | ApplicationEnvironmentPreparedEvent | 1.0 |
contextPrepared(ConfigurableApplicationContext) | ||
contextLoaded(ConfigurableApplicationContext) | ApplicationPreparedEvent | 1.0 |
started(ConfigurableApplicationContext) | ApplicationStartedEvent | 2.0 |
running(ConfigurableApplicationContext) | ApplicationReadyEvent | 2.0 |
failed(ConfigurableApplicationContext,Throwable) | ApplicationFailedEvent | 1.0 |
contextPrepared不对应事件,contextLoaded对应ApplicationPreparedEvent事件
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableEnvironment 实例:
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
prepareEnvironment:
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);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
getOrCreateEnvironment:
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableApplicationContext 实例:
context = createApplicationContext();
createApplicationContext:
protected ConfigurableApplicationContext createApplicationContext() {
Class> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 根据构造阶段推断的 Web 应用类型来创建Spring应用上下文
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);
}