博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot(1)—启动原理之SpringApplication对象的创建
阅读量:4029 次
发布时间:2019-05-24

本文共 3907 字,大约阅读时间需要 13 分钟。

创建SpringApplication对象

SpringBoot版本为 2.1.1.RELEASE

@SpringBootApplicationpublic 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类的构造方法。

下面将会重点说明一下这个构造方法:
1. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
这行代码是将启动类存储到SpringApplicationd对象的primarySources 属性中
2. 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

  1. setInitializers((Collection) getSpringFactoriesInstances(
    ApplicationContextInitializer.class));

这个方法是用来加载Spring应用上下文初始化器的。

我们debug进入getSpringFactoriesInstances() 中:

private 
Collection
getSpringFactoriesInstances(Class
type) { return getSpringFactoriesInstances(type, new Class
[] {}); } private
Collection
getSpringFactoriesInstances(Class
type, Class
[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates Set
names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List
instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }

其实这个方法就是通过SpringFactoriesLoader类的loadFactoryNames()方法从类路径下的 “META-INF/spring.factories” 文件中找到所有的 “ApplicationContextInitializer”,然后保存到 SpringApplication的initializers属性中。

在这里插入图片描述

在这里插入图片描述
在下图中,我们可以看到通过getSpringFactoriesInstances()方法,initializers属性中保存了6个初始化器
在这里插入图片描述

  1. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    和上个方法类似,只不过这个方法是加载Spring应用事件监听器,但是原理是 一样的,都是利用SpringFactoriesLoader类的loadFactoryNames()方法,只不过这个初始化的对象变成了ApplicationListener

在这里插入图片描述

5. this.mainApplicationClass = deduceMainApplicationClass();
这个方法的作用是从多个配置类中找到含有main方法的主配置类

在这里插入图片描述

其实这个方法设计的并不严谨,因为在SpringApplication.run(XXX.class)方法中,这个class对象并一定要传入其主配置类,因为我们知道@SpringBootApplication 元标注 @EnableAutoConfiguration,它们的作用基本相同,换言之,这里的class 对象我们可以传入任意标注了@EnableAutoConfiguration、@Configuration两个注解的类。

下一篇文章将会讲解SpringApplicaiton中run()方法的运行。

转载地址:http://xqmbi.baihongyu.com/

你可能感兴趣的文章
关于信息检索(IR)、搜索引擎的学与思
查看>>
关于广告、推荐中的CTR的学于思
查看>>
文本分类
查看>>
自然语言处理中的Attention机制
查看>>
pbc 的使用
查看>>
luasocket 安装遇到的问题
查看>>
lua读写redis的环境部署
查看>>
Using MIT-Scheme in MacOS X on the Command Line
查看>>
php redis 接口说明
查看>>
cocos2dx使用lua和protobuf
查看>>
lua5.2 可能会遇到的一些错误
查看>>
C语言编译过程
查看>>
stirling formula prove
查看>>
关于数字类型转化为整型的方法
查看>>
PHP 常用正则表达式整理
查看>>
自然计算
查看>>
自然计算时间复杂度杂谈
查看>>
当前主要目标和工作
查看>>
系统菜单
查看>>
路漫漫其修远兮,吾将上下而求索(2)
查看>>