一、SpringApplication基本使用
运行
// 运行
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);
通过 SpringApplicationBuilder API 调整
new SpringApplicationBuilder(SpringApplicationApplication.class)
.bannerMode(Banner.Mode.CONSOLE)
.web(WebApplicationType.NONE)
.profiles("prod")
.headless(true);
二、SpringApplication构造阶段
核心代码如下,以下小节均基于此构造函数分析
/**
* 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();
}
配置 Spring Boot Bean 源
Java 配置 Class 或 XML 上下文配置文件集合,用于 Spring Boot BeanDefinitionLoader 读取 ,并且将配置源解析加载为
- Spring Bean 定义
- 数量:一个或多个以上
启动配置Bean源
-
第一种
@SpringBootApplication
注解标注的类,不仅限于本身,eg:public static void main(String[] args) { // 运行 SpringApplication.run(ApplicationApplication.class, args); } @SpringBootApplication public static class ApplicationApplication{ }
-
第二种通过
setSources
配置:``,eg:
setSources
源码:
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{
}
推断 Web 应用类型
根据是否存在某个类来判断当前应用类型: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 }
由以上代码可知:
- web.reactive和web.servlet共存时,返回
SERVLET
应用环境,只存在WEBFLUX_INDICATOR_CLASS
时,才为WebApplicationType.REACTIVE
- 当
SERVLET_INDICATOR_CLASSES
中类均不存在时,返回return WebApplicationType.NONE
- 默认返回
WebApplicationType.SERVLET
加载应用上下文初始器 ( ApplicationContextInitializer ) & 加载应用事件监听器( ApplicationListener )
利用 Spring 工厂加载机制,实例化 ApplicationContextInitializer 实现类,并排序对象集合。
- 实现类: org.springframework.core.io.support.SpringFactoriesLoader
- 配置资源: META-INF/spring.factories
- 排序: AnnotationAwareOrderComparator#sort
SpringApplicationg构造函数中加载代码如下:
- org.springframework.boot.SpringApplication#SpringApplication
- SpringApplication:
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
实际调用方法:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 通过工厂机制获取实现类名字 SpringFactoriesLoader->META-INF/spring.factories->names
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 创建实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 根据order排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
推断引导类(Main Class)
通过异常堆栈来判断符合条件(包含main方法)的类
- org.springframework.boot.SpringApplication#SpringApplication
- SpringApplication:this.mainApplicationClass = deduceMainApplicationClass();
- 源码和
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;
}
三、SpringApplication.run运行阶段
核心代码
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);
}
}
加载 SpringApplication 运行监听器( SpringApplicationRunListeners )
核心代码
// 加载监听器
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));
}
运行 SpringApplication 运行监听器( SpringApplicationRunListeners )
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 事件 / Spring 事件
Spring Boot 通过 SpringApplicationRunListener 的实现类 EventPublishingRunListener 利用 Spring Framework 事件API ,广播 Spring Boot 事件。
Spring Framework 事件/监听器编程模型
- Spring 应用事件
- 普通应用事件: ApplicationEvent
- 应用上下文事件: ApplicationContextEvent
- Spring 应用监听器
- 接口编程模型: ApplicationListener
- 注解编程模型: @EventListener
- Spring 应用事广播器
- 接口: ApplicationEventMulticaster
- 实现类: SimpleApplicationEventMulticaster
- 执行模式:同步或异步
EventPublishingRunListener 监听方法与 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事件
创建 Environment
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableEnvironment 实例:
- Web Reactive: StandardEnvironment
- Web Servlet: StandardServletEnvironment
- 非 Web: StandardEnvironment
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();
}
}
创建 Spring 应用上下文( ConfigurableApplicationContext )
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableApplicationContext 实例:
- Web Reactive: AnnotationConfigReactiveWebServerApplicationContext
- Web Servlet: AnnotationConfigServletWebServerApplicationContext
- 非 Web: AnnotationConfigApplicationContext
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);
}