SpringApplication类的直接作用是在main方法中通过自有的run方法启动spring应用
一般的,在idea新建spring boot 工程之后会有一个启动类,执行main方法也就启动了spring应用
@SpringBootApplication
public class HouseWebApplication {
public static void main(String[] args) {
SpringApplication.run(HouseWebApplication.class, args);
}
}
基础技术以及衍生技术
Spring Framework
Spring 模式注解
Spring 应用上下文
Spring工厂加载机制
Spring应用上下文初始器
Spring Environment抽象
Spring应用事件/监听
构建在SpringBoot之上的技术
SpringApplication
SpringApplication Build API
SpringApplication 运行监听器
SpringAppliction 参数
SpringApplication 故障分析
SpringBoot应用事件/监听
SpringApplication 准备阶段
SpringApplication的准备阶段也可以说是构造器阶段,可以来看一看源码
public SpringApplication(Class... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
// 第一部分 配置源
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 第二部分 推断Web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 第三部分 应用上下文初始器 和 应用事件监听器
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 第四部分 :推导引用主类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
配置Spring Bean 的源
可以看到 如上的引导类配置了一个模式注解 @SpringBootApplication

显而易见 可以通过JAVA配置Class 这也是Spring的模式注解.
Java 配置 Class 或 XML 上下文配置文件集合,用于 Spring Boot BeanDefinitionLoader 读取 ,并且将配置源解析加载为
Spring Bean 定义
数量:一个或多个以上
-
Java 配置 Class
用于 Spring 注解驱动中 Java 配置类,大多数情况是 Spring 模式注解所标注的类,如 @Configuration 。 -
XML 上下文配置文件
用于 Spring 传统配置驱动中的 XML 文件。
SpringApplication中有setSource的方法
我们可以看到注释中的英文解释,参数可以类名,包名以及XML源路径。
Spring Boot 通过BeanDefinitionLoader 中的构造方法分别加载两种数据源
/**
* Set additional sources that will be used to create an ApplicationContext. A source
* can be: a class name, package name, or an XML resource location.
* <p>
* Sources set here will be used in addition to any primary sources set in the
* constructor.
* @param sources the application sources to set
* @see #SpringApplication(Class...)
* @see #getAllSources()
*/
public void setSources(Set<String> sources) {
Assert.notNull(sources, "Sources must not be null");
this.sources = new LinkedHashSet<>(sources);
}
/**
* Create a new {@link BeanDefinitionLoader} that will load beans into the specified
* {@link BeanDefinitionRegistry}.
* @param registry the bean definition registry that will contain the loaded beans
* @param sources the bean sources
*/
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
this.sources = sources;
//JAVA 配置CLASS
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
//XML配置
this.xmlReader = new XmlBeanDefinitionReader(registry);
if (isGroovyPresent()) {
this.groovyReader = new GroovyBeanDefinitionReader(registry);
}
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
案例 :自定义读取配置源
public class SpringApplicationBootstrap {
public static void main(String[] args) {
// SpringApplication.run(ApplicationConfiguration.class,args);
Set<String> sources = new HashSet();
// 配置Class 名称
sources.add(ApplicationConfiguration.class.getName());
SpringApplication springApplication = new SpringApplication();
springApplication.setSources(sources);
springApplication.run(args);
}
@SpringBootApplication
public static class ApplicationConfiguration {
}
}
推断Web应用类型
根据当前应用ClassPath中是否存在相关实现类来推断Web应用的类型,包括:
- Web Reactive: WebApplication.REACTIVE
- Web Servlet: WebApplication.SERVLET
- 非Web:WebApplication.NONE
参考方法 :org.springframework.boot.WebApplicationType#deduceFromClasspath
//默认Web应用的类型为servlet
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
当然可以在启动类中指定WebApplicationType 的类型
推断引导类

根据Main线程执行堆栈判断实际的引导类;
不需要主动传递main,通过遍历推断方式来推导。
参考方法:org.springframework.boot.SpringApplication#deduceMainApplicationClass
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();
StackTraceElement[] var2 = stackTrace;
int var3 = stackTrace.length;
for(int var4 = 0; var4 < var3; ++var4) {
StackTraceElement stackTraceElement = var2[var4];
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException var6) {
;
}
return null;
}
加载应用上下文初始器(ApplicationContextInitializer)
利用 Spring 工厂加载机制,实例化 ApplicationListener 实现类,并排序对象集合
org.springframework.boot.SpringApplication#getSpringFactoriesInstances
实现:

技术:
1、实现类:org.springframework.core.io.support.SpringFactoriesLoader
2、配置资源:META-INF/spring.factories (源码可见)
3、排序:org.springframework.core.annotation.AnnotationAwareOrderComparator#sort(java.util.List<?>)
加载 SpringApplication 运行监听器( SpringApplicationRunListeners )
利用 Spring 工厂加载机制,读取 SpringApplicationRunListener 对象集合,并且封装到组合类
SpringApplicationRunListeners
加载方式和加载应用上下文初始器一样

SpringApplication运行阶段
所谓的运行阶段,也就是run方法执行,可以先看一下源码
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
*
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
// 1.计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 声明上下文
ConfigurableApplicationContext context = null;
// 声明异常报告集合
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 2.设置headless模式 就是设置系统属性java.awt.headless(不需要关注)
configureHeadlessProperty();
// 3.使用工厂方法模式 加载SpringApplication运行监听器(SpringApplicationRunListeners)
SpringApplicationRunListeners listeners = getRunListeners(args);
// 使用组合对象的设计模式 迭代的执行starting()
listeners.starting();
try {
// 获取默认的应用参数 (不关注)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 4.创建配置Environment(不关注)
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
// 打印Banner(不关注)
Banner printedBanner = printBanner(environment);
// 5.创建spring-boot上下文
context = createApplicationContext();
// 获取启动错误报告实例
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);
// 6.上下文启动之前准备
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 7.刷新上下文
refreshContext(context);
// 8.刷新后处理
afterRefresh(context, applicationArguments);
// 计时结束
stopWatch.stop();
// 打印日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 监听spring上下文,此时上下文已启动,Spring Bean已初始化完成
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;
}
-
加载:SpringApplication 运行监听器
-
运行:SpringApplication 运行监听器
创建:应用上下文,Environment 失败:故障分析报告 回调:CommandLineRunner,ApplicationRunner -
监听:SpringBoot事件,Spring事件
加载SpringApplication运行监听器(SpringApplicationRunListeners)
利用Spring工厂加载机制,读取SpringApplicationRunListener对象集合,并且封装到组合类SpringApplicationRunListeners
/**
* Listener for the {@link SpringApplication} {@code run} method.
* {@link SpringApplicationRunListener}s are loaded via the {@link SpringFactoriesLoader}
* and should declare a public constructor that accepts a {@link SpringApplication}
* instance and a {@code String[]} of arguments. A new
* {@link SpringApplicationRunListener} instance will be created for each run.
*
* @author Phillip Webb
* @author Dave Syer
* @author Andy Wilkinson
*/
public interface SpringApplicationRunListener {
/**
* Spring刚启动
*/
void starting();
/**
* ConfigurableEnvironment 准备妥当,允许将其调整
*/
void environmentPrepared(ConfigurableEnvironment environment);
/**
* ConfigurableApplicationContext 准备妥当,允许将其调整
*/
void contextPrepared(ConfigurableApplicationContext context);
/**
* ConfigurableApplicationContext 已装载,但仍未启动
*/
void contextLoaded(ConfigurableApplicationContext context);
/**
* ConfigurableApplicationContext 已启动,此时 Spring Bean 已初始化完成
*/
void started(ConfigurableApplicationContext context);
/**
* Spring 应用正在运行
*/
void running(ConfigurableApplicationContext context);
/**
* Spring 应用运行失败
*/
void failed(ConfigurableApplicationContext context, Throwable exception);
}
监听SpringBoot事件,Spring事件
SpringBoot通过SpringApplicationRunListener 实现类EventPublishingRunlistener 利用Spring Framework 事件API,广播SpringBoot事件

SpringFramework 事件/监听器编程模型
Spring应用事件
普通应用事件:ApplicationEvent
应用上下文事件:ApplicationContextEvent
Spring应用监听器
接口编程模型:ApplicationListener
注解编程模型:EventListener
Spring应用事件广播器
接口ApplicationEventMulticaster
实现类 SimpleApplicationEventMulticaster
执行模式: 同步或者异步
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//异步执行
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
//同步执行
else {
invokeListener(listener, event);
}
}
}
创建 Spring 应用上下文( ConfigurableApplicationContext )
根据准备阶段的推断Web应用类型创建对应的ConfigurableApplicationContext实例:
Web Reactive: AnnotationConfigReactiveWebServerApplicationContext
Web Servlet: AnnotationConfigServletWebServerApplicationContext
非 Web: AnnotationConfigApplicationContext
创建 Environment
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableEnvironment 实例:
Web Reactive: StandardEnvironment
Web Servlet: StandardServletEnvironment
非 Web: StandardEnvironment


被折叠的 条评论
为什么被折叠?



