创建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对象的创建的更多相关文章

  1. springboot之启动原理解析

    前言 SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面 ...

  2. springboot之启动原理解析及源码阅读

    前言 SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面 ...

  3. SpringBoot FatJar启动原理

    目录 SpringBoot FatJar启动原理 背景 储备知识 URLStreamHandler Archive 打包 SpringBoot启动 扩展 SpringBoot FatJar启动原理 背 ...

  4. (转)springboot应用启动原理(二) 扩展URLClassLoader实现嵌套jar加载

    转:https://segmentfault.com/a/1190000013532009 在上篇文章<springboot应用启动原理(一) 将启动脚本嵌入jar>中介绍了springb ...

  5. 【SpringBoot】 理解SpringBoot的启动原理

    前言 前文已经介绍了Spring Bean的生命周期,那么使用过程中发现SpringBoot 的启动非常快捷,本文将介绍SpringBoot的内部启动原理. 启动过程 如上图所示,我们先分析下Spri ...

  6. (转)springboot应用启动原理(一) 将启动脚本嵌入jar

    转:https://segmentfault.com/a/1190000013489340 Spring Boot Takes an opinionated view of building prod ...

  7. 【转】Spring Boot干货系列:(三)启动原理解析

    前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开Sprin ...

  8. Spring Boot干货系列:(三)启动原理解析

    Spring Boot干货系列:(三)启动原理解析 2017-03-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说 ...

  9. Spring Boot启动原理解析

    Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置 ...

随机推荐

  1. 虚拟化网络之OpenvSwitch

    OpenvSwitch简称OVS,官网(http://openvswitch.org/) OVS是一个高质量.多层的虚拟交换软件,即虚拟交换机. OpenvSwitch的见的相关组件: ovs-vsw ...

  2. python处理txt文件的一种情况

    在txt文本中,以换行符作为标记分段处理txt文件中的内容的方法: with open(path, 'r', encoding='utf-8') as f: for line in f: if lin ...

  3. 简易html5贪吃蛇

    1. [图片] E6~0%QPA46ER843UQJ$0Z`H.jpg ​2. [文件] snake.html <!DOCTYPE html><html><head> ...

  4. html5--1.15 style元素与HTML样式基础

    html5--1.15 style元素与HTML样式基础 学习要点: 1.引入样式的三种方式2.了解style元素插入内联样式表与内部样式表 1.引入样式的三种方式 1.外部样式表:通过 link元素 ...

  5. Promise 入门与使用

    Tags: ECMAScript6 参考资料 promises-book Promise对象 we-have-a-problem-with-promises Promise最初被提出是在 E语言中, ...

  6. linux命令学习笔记(45):free 命令

    free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存,及被内核使用的buffer.在Linux系统监控的 工具中,free命令是最经常使用的命令之一. .命令格式: free [参 ...

  7. hdfs 查看报告--命令(hdfs dfsadmin -report)

    [hadoop@master sbin]$ hdfs dfsadmin -reportConfigured Capacity: 8202977280 (7.64 GB)Present Capacity ...

  8. 【Lintcode】013.strStr

    题目: For a given source string and a target string, you should output the first index(from 0) of targ ...

  9. 【Python】File IO

    1.numpy.genfromtxt() numpy.genfromtxt() CSV文件很容易被numpy类库的genfromtxt方法解析 2.

  10. 【LeetCode】040. Combination Sum II

    题目: Given a collection of candidate numbers (C) and a target number (T), find all unique combination ...