SpringBoot(1)—启动原理之SpringApplication对象的创建
创建SpringApplication对象
SpringBoot版本为 2.1.1.RELEASE
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
这是一个SpringBoot项目的启动类,在主方法内,调用了SpringApplication类的静态run( )方法,并且把启动类的字节码和主方法的参数作为函数入参。
我们以Debug方式来运行代码,可以发现SpringBoot项目在启动时会先创建SpringApplication对象。具体代码如下:
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
public SpringApplication(Class<?>... primarySources) {
this(null, 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();
}
可以发现,其实在创建SpringApplcation对象时就是把启动类的Class类作为入参调用了SpringApplication类的构造方法。
下面将会重点说明一下这个构造方法:
A: this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
这行代码是将启动类存储到SpringApplicationd对象的primarySources 属性中
B: this.webApplicationType = WebApplicationType.deduceFromClasspath();
这个方法是推断Web应用类型
static WebApplicationType deduceFromClasspath() {
//存在DispatcherHander但是不存在DispatcherServlet时,推断为WebFlux类型
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
// 当Servlet和ConfigurableWebApplicationContext均不存在时,推断为非Web应用
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
由于我们只引入了web依赖,所以返回为Servlet
C: setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
这个方法是用来加载Spring应用上下文初始化器的。
我们debug进入getSpringFactoriesInstances() 中:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new 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
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
其实这个方法就是通过SpringFactoriesLoader类的loadFactoryNames()方法从类路径下的 "META-INF/spring.factories" 文件中找到所有的 "ApplicationContextInitializer",然后保存到 SpringApplication的initializers属性中。
在下图中,我们可以看到通过getSpringFactoriesInstances()方法,initializers属性中保存了6个初始化器
D: setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
和上个方法类似,只不过这个方法是加载Spring应用事件监听器,但是原理是 一样的,都是利用SpringFactoriesLoader类的loadFactoryNames()方法,只不过这个初始化的对象变成了ApplicationListener
E: this.mainApplicationClass = deduceMainApplicationClass();
这个方法的作用是从多个配置类中找到含有main方法的主配置类
其实这个方法设计的并不严谨,因为在SpringApplication.run(XXX.class)方法中,这个class对象并一定要传入其主配置类,因为我们知道@SpringBootApplication 元标注 @EnableAutoConfiguration,它们的作用基本相同,换言之,这里的class 对象我们可以传入任意标注了@EnableAutoConfiguration、@Configuration两个注解的类。
下一篇文章将会讲解SpringApplicaiton中run()方法的运行。
SpringBoot(1)—启动原理之SpringApplication对象的创建的更多相关文章
- springboot之启动原理解析
前言 SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面 ...
- springboot之启动原理解析及源码阅读
前言 SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面 ...
- SpringBoot FatJar启动原理
目录 SpringBoot FatJar启动原理 背景 储备知识 URLStreamHandler Archive 打包 SpringBoot启动 扩展 SpringBoot FatJar启动原理 背 ...
- (转)springboot应用启动原理(二) 扩展URLClassLoader实现嵌套jar加载
转:https://segmentfault.com/a/1190000013532009 在上篇文章<springboot应用启动原理(一) 将启动脚本嵌入jar>中介绍了springb ...
- 【SpringBoot】 理解SpringBoot的启动原理
前言 前文已经介绍了Spring Bean的生命周期,那么使用过程中发现SpringBoot 的启动非常快捷,本文将介绍SpringBoot的内部启动原理. 启动过程 如上图所示,我们先分析下Spri ...
- (转)springboot应用启动原理(一) 将启动脚本嵌入jar
转:https://segmentfault.com/a/1190000013489340 Spring Boot Takes an opinionated view of building prod ...
- 【转】Spring Boot干货系列:(三)启动原理解析
前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开Sprin ...
- Spring Boot干货系列:(三)启动原理解析
Spring Boot干货系列:(三)启动原理解析 2017-03-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说 ...
- Spring Boot启动原理解析
Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置 ...
随机推荐
- debian7配置
输入法: apt-get install ibus ibus-pinyin 并执行ibus-setup进行配置,首选项->输入法->中文,然后按添加按钮即可. 软件开发基本软件:apt-g ...
- linux系统调用mount全过程分析【转】
本文转载自:https://blog.csdn.net/skyflying2012/article/details/9748133 系统调用本身是软中断,使用系统调用,内核也陷入内核态,异常处理,找到 ...
- C# 序列化反序列化 list<>
public class XMLTest { [Test] public static void Test() { Name1 name = new Name1(); name.Id = " ...
- Contiki Rtimer 模块
一.rtimer概述 The Contiki rtimer library provides scheduling and execution of real-time tasks (with pre ...
- 分享知识-快乐自己:Hibernate 关联映射
关联关系映射--概念: 关联关系是使用最多的一种关系,非常重要.在内存中反映为实体关系,映射到DB中为主外键关系. 实体间的关联,即对外键的维护.关联关系的发生,即对外键数据的改变. 外键:外面的主键 ...
- python基础-文本操作
文件IO #文件的基本操作 1.在python中你可以用file对象做大部分的文件操作 2.一般步骤: 先用python内置的open()函数打开一个文件,并创建一个file对象, 然后调用相关方法进 ...
- 查询oracle 数据库 SQL语句执行情况
1.查看总消耗时间最多的前10条SQL语句 select * from (select v.sql_id, v.child_number, v.sql_text, v.elapsed_time ...
- [转]ECMAScript5 Object的新属性方法
虽然说现在并不是所有的浏览器都已经支持ECMAScript5的新特性,但相比于ECMAScript4而言ECMAScript5被广大浏览器厂商广泛接受,目前主流的浏览器中只有低版本的IE不支持,其它都 ...
- BZOJ3648:寝室管理
浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem. ...
- bzoj 2067 [Poi2004]SZN——二分+贪心
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2067 最少的线段可以贪心地想出来.(结果还是写错了)就是偶数孩子可以自己配对,奇数孩子要带一 ...