一个简单的SB程序如下,点击main方法左边的原谅色的三角形就能把程序启动起来,虽然什么功能都没有,但是启动做了很多处理,加载了很多支持多种功能的组件(类似使用new ClassPathXmlApplicationContext()
启动一个Spring程序,其中加载了很多东西)
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
分析的入口就是从SpringApplication的run方法开始,而@SpringBootApplication
注解在后续的处理中会用到,所以暂时忽略
1.入口
进入run方法
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);
}
2.初始化SpringApplication
首先初始化了SpringApplication
,然后再调用其run方法,那么先看下SpringApplication的构造方法里的逻辑
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 即demo里的SpringBootDemoApplication对应的Class对象集合
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 应用的类型,共三种类型
// reactive、servlet 、非web应用
this.webApplicationType = deduceWebApplicationType();
// 获取spring.factories中配置的ApplicationContextInitializer的实现类并实例化,最后放到集合当中
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 原理同上
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 找到执行main方法的那个类的Class对象,即demo中的SpringBootDemoApplication对应的Class对象
this.mainApplicationClass = deduceMainApplicationClass();
}
2.1获取应用类型
在SpringApplication
构造方法里,调用了deduceWebApplicationType
来判断是什么类型的应用,那么SpringBoot是如何判断的呢?往里进去看下具体实现
private WebApplicationType deduceWebApplicationType() {
//REACTIVE_WEB_ENVIRONMENT_CLASS = org.springframework.web.reactive.DispatcherHandler
//MVC_WEB_ENVIRONMENT_CLASS = org.springframework.web.servlet.DispatcherServlet
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
//WEB_ENVIRONMENT_CLASSES=javax.servlet.Servlet
// 或者org.springframework.web.context.ConfigurableWebApplicationContext
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
ClassUtils.isPresent
方法中尝试加载传入的类,如果加载成功,则返回true,如果失败则返回false,SpringBoot使用这种方式在判断当前是什么类型的应用。
从假设我们应用中什么依赖都没有加入,那么WEB_ENVIRONMENT_CLASSES
、REACTIVE_WEB_ENVIRONMENT_CLASS
或者MVC_WEB_ENVIRONMENT_CLASS
都是加载失败的,最终返回WebApplicationType.NONE
。
从另一个方面来说,如果我们想构建一个SpringMVC的web应用,那么只需要加入如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
此时,SpringBoot会帮我们间接依赖SpringMVC所需要的包,那么就间接引入了org.springframework.web.context.Conf