一、前言

  • Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去。
  • 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot源码管中窥豹系列。

二、项目类型

这一节我们先讨论一下springboot项目的怎么自动加载applicationcontext实现类的。

  • 以前的spring的项目,都是xml加载bean,常用的都是XmlWebApplicationContext实现类
  • 后来出现注解的形式,基本用AnnotationConfigWebApplicationContext实现类
  • 后来又出现响应式编程reactive

那springboot用的是哪一种呢?

三、源码解读

先说结论:关于类型的选择,springboot是根据class来判断的。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {

    ...

    this.webApplicationType = WebApplicationType.deduceFromClasspath();

    ...

}
  • 我们从SpringApplication的构造函数开始看起
  • 构造函数里面有段代码:是确定类型的

我们先看类型:

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"; static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
  • 第一段if,如果存在reactive包的DispatcherServlet,同时不存在jersey和mvc的DispatcherHandler,就是REACTIVE
  • 第二段循环,不存在Servlet或者ConfigurableWebApplicationContext,就是none
  • 剩下的就是我们熟悉的SERVLET

类型确定之后,我们看SpringApplication的run方法:

public ConfigurableApplicationContext run(String... args) {

    ...

    try {
... context = createApplicationContext(); ...
} catch (Throwable ex) { ... } ... return context;
}

ApplicationContext实现类就是在createApplicationContext()里面确定的

public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext"; public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext"; public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"; protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
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);
}

根据类型加载不同的class:

  • 如果是SERVLET:AnnotationConfigServletWebServerApplicationContext
  • 如果是REACTIVE:

    AnnotationConfigReactiveWebServerApplicationContext
  • default:AnnotationConfigApplicationContext

至此,一目了然了,想要不同的项目类型,添加对应的jar包,springboot自动帮你选择对应的ApplicationContext实现类

如果是普通的web项目:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

如果是reactive项目:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

如果是非web项目:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

欢迎关注公众号:丰极,更多技术学习分享。

springboot源码解析-管中窥豹系列之项目类型(二)的更多相关文章

  1. springboot源码解析-管中窥豹系列之web服务器(七)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  2. springboot源码解析-管中窥豹系列

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  3. springboot源码解析-管中窥豹系列之BeanDefine如何加载(十三)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  4. springboot源码解析-管中窥豹系列之BeanPostProcessor(十二)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  5. springboot源码解析-管中窥豹系列之bean如何生成?(十四)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  6. springboot源码解析-管中窥豹系列之BeanDefinition(八)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  7. springboot源码解析-管中窥豹系列之自动装配(九)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  8. springboot源码解析-管中窥豹系列之EnableXXX(十)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  9. springboot源码解析-管中窥豹系列之BeanFactoryPostProcessor(十一)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

随机推荐

  1. PyQt(Python+Qt)学习随笔:Model中项的标记flags取值及枚举类型Qt.ItemFlag

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 在Model中的项可以通过flags()方法查询对应项是否能被选择.拖拽或其他操作,对应的返回值类型 ...

  2. PyQt(Python+Qt)学习随笔:Designer中的QDialogButtonBox的按钮改变缺省文字的方法

    在Qt Designer中可以预先定义标准按钮,相关支持的标准按钮请见<PyQt(Python+Qt)学习随笔:Designer中的QDialogButtonBox的StandardButton ...

  3. NodeService Ensure that Node.js is installed and can be found in one of the PATH directories

    今天发布NodeService到服务器,服务器环境是window server 2012 一直报错: [1] Ensure that Node.js is installed and can be f ...

  4. CF1147F Zigzag Game & 稳定婚姻问题学习笔记

    CF1147F Zigzag Game 这题太神仙了,不得不记录一下. 我网络流做不动了,DS做不动了,DP做不动了,特别自闭.于是博弈论之神(就是随手切3500博弈的那种) \(\color{bla ...

  5. KVM初体验之virt-manager unable to connect to libvirt的处理办法

    解决方法 需要用root身份运行virt-manager

  6. 八、git学习之——忽略特殊文件、配置别名、搭建git服务器

    原文来自 一.忽略特殊文件 有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files . ...

  7. Day5 - 01 函数及函数的调用概念

    函数就是最基本的一种代码抽象的方式.函数只需写一次,就可以多次调用.Python本身内置了很多有用的函数,可以直接调用. 调用函数    要调用一个函数,需要知道函数的名称和参数.可以通过help(x ...

  8. Docker 安装并部署Tomcat、Mysql8、Redis

    1.  安装前检查 1 #ContOS 7安装Docker系统为64位,内核版本为3.10+ 2 lsb_release -a 3 4 uname -r 5 6 #更新yum源 7 yum -y up ...

  9. Asp.net core验证类ModelStateDictionary的bug

    在使用.net core 3.1 时发现明明没有验证请求类属性,甚至已经加了默认值 但是验证类时依然会报错 经过网上百度等搜索,尝试使用可空类型赋值默认值 果然验证类没有报错 不清楚是微软的bug还是 ...

  10. SMART

    SMART原则: S(Specific):目标必须是具体的,要对标特定的工作指标,不能笼统: M(Measurable):目标必须是可衡量的,衡量的指标是数量化或者行为化的,验证这些指标的数据或者信息 ...