目录:Springboot源码学习目录上文:01、SpringBoot 目录
前言:SpringBoot的启动的流程主要包含两大块,第一部分是实例化Spring应用程序SpringApplication对象,第二部分是,执行SpringApplicationrun方法,其中核心的工厂创建,配置文件解析,自动装配,IOC逻辑都在run方法中,本篇文章主要讲解第一部分

一、实例化 SpringApplication

创建启动一个SpringBoot Demo应用,进行debug

public static void main(String[] args) {
        SpringApplication.run(SpringbootDemoApplication.class, args);
    }

上一步中,debug 进入run方法,如下

// primarySource : com.example.springbootdemo.SpringbootDemoApplication
    // args : 程序启动时的 虚拟机选项或者 程序参数,此处没有配置,所以为空
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class<?>[] { primarySource }, args);
    }

上一步中 debug 继续点击进入run方法,如下

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        // 这里面就是SpringBoot启动的两大步骤,先实例化Spring应用程序, 然后调用SpringApplication的run方法
        // 我们这里只看第一步
	return new SpringApplication(primarySources).run(args);
    }

继续 debug 进入SpringApplication 的实例化过程

public SpringApplication(Class<?>... primarySources) {
	this(null, primarySources);
    }

继续debug进入 this,进入实例化过程中的核心逻辑

// resourceLoader : null
    // primarySources : [com.example.springbootdemo.SpringbootDemoApplication]
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // 初始化 资源加载属性,传入的为 null
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
        // 初始化 核心来源类属性
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 初始化 web应用类型,见下面1
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 初始化 引导注册表初始化后增强器,见下面2,作用是在引导上下文创建后回调,对引导上下文进行增强
	this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
        // 初始化 应用上下文初始化后增强器,见下面3,作用是在应用上下文创建后,准备应用上下文逻辑里回调,对应用上下文进行增强
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // 初始化 应用监听器,见下面3,作用是在在spring应用的创建整个过程中对发生的事件进行处理
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 出事主应用程序的启动类,就是 com.example.springbootdemo.SpringbootDemoApplication
	this.mainApplicationClass = deduceMainApplicationClass();
    }

1、推断web应用类型

static WebApplicationType deduceFromClasspath() {
        // 当类路径下存在 org.springframework.web.reactive.DispatcherHandler 类并且不存在 org.springframework.web.servlet.DispatcherServlet 和 org.glassfish.jersey.servlet.ServletContainer
        // web应用类型为REACTIVE 响应式 web 应用
	if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
	      return WebApplicationType.REACTIVE;
	}
        // 当类路径下 javax.servlet.Servlet 和org.springframework.web.context.ConfigurableWebApplicationContext都不存在
        // web应用类型为NONE 当前应用不是web应用
	for (String className : SERVLET_INDICATOR_CLASSES) {
	      if (!ClassUtils.isPresent(className, null)) {
		    return WebApplicationType.NONE;
	      }
	}
        // 以上类型都不是
        // web应用类型为SERVLET 常用的servlet web 应用
	return WebApplicationType.SERVLET;
    }

2、从spring.factories 中获取 BootstrapRegistryInitializer

private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
	ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
        // 从spring.factories 中获取Bootstrapper集合,详见3;然后遍历转化为BootstrapRegistryInitializer,再存入 initializers
	getSpringFactoriesInstances(Bootstrapper.class).stream()
			.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
			.forEach(initializers::add);
        // 从spring.factories 中获取BootstrapRegistryInitializer集合,再存入 initializers
	initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
	return initializers;
    }

3、 从spring.factories 中获取指定类型的实现类集合

// 上面说到的从spring.factories中获取 ApplicationContextInitializer,ApplicationListener,Bootstrapper,BootstrapRegistryInitializer等接口实现类的集合,的统一收口方法
    // 该方法在整个启动流程中会频繁出现
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
	return getSpringFactoriesInstances(type, new Class<?>[] {});
    }

继续debug调用重载的方法

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// Use names and ensure unique to protect against duplicates
        // SpringFactoriesLoader.loadFactoryNames(type, classLoader) spring的spi技术,获取spring.factories配置文件中已经配置的指定类型的的实现类集合
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 通过反射创建这些类
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
    }

spring的SpringFactoriesLoader 我们再次就不细看了,会在SpringBoot spring.factories 配置文件的工厂模式一文中进行讲解
我们继续debug进入createSpringFactoriesInstances()方法,就是利用反射将获取到的类实例化

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
	ClassLoader classLoader, Object[] args, Set<String> names) {
	List<T> instances = new ArrayList<>(names.size());
	for (String name : names) {
		try {
			Class<?> instanceClass = ClassUtils.forName(name, classLoader);
			Assert.isAssignable(type, instanceClass);
			Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
			T instance = (T) BeanUtils.instantiateClass(constructor, args);
			instances.add(instance);
		}
		catch (Throwable ex) {
			throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
		}
	}
	return instances;
    }

二、总结

核心的逻辑就是在实例化过程中初始化了各种属性

  • webApplicationType(web应用类型) : 作用是在后面创建应用上下文的时候,指导创建那种上下文
  • bootstrapRegistryInitializers(引导注册表初始化后增强器):作用是在引导上下文创建后回调,对引导上下文进行增强
  • initializers(应用程序上下文初始化后增强器):作用是在应用上下文创建后,准备应用上下文逻辑里回调,对应用上下文进行增强
  • listeners(应用程序监听器):作用是在在spring应用的创建整个过程中对发生的事件进行处理,大概如下
  • starting:第一次执行SpringApplicationrun方法时调用,可以做一些非常早期的初始化工作
  • environmentPrepared :在准备好运行环境后,在创建应用上下文ApplicationContext之前调用,主要有配置文件的加载
  • contextPrepared : 在创建应用上下文ApplicationContext后,但在加载源之前调用
  • contextLoaded :在加载应用程序上下文ApplicationContext的源后但在刷新之前调用
  • started :上下文已刷新,应用程序已启动,但尚未调用CommandLineRunner和ApplicationRunner。
  • running :在run方法完成之前立即调用,此时应用程序上下文已刷新,并且所有CommandLineRunner和ApplicationRunner都已调用
  • failed : 在运行应用程序时发生故障时调用

三、启动流程图

spring boot 工作流程 spring boot执行流程_SpringBoot