一、前言
- 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:
Annota56ctionConfigReactiveWebServerApplicationContext - 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源码解析-管中窥豹系列
欢迎关注公众号:丰极,更多技术学习分享。