spring boot 源码解析 启动流程

spring boot 源码解析 启动流程

在面试过程中经常被问到过spring boot的启动流程,今天就翻一下源码整体看一下;

首先,新建一个启动类,可以看到是首先调用的SpringApplication的静态方法run

@SpringBootApplication
public class SourceReadApplillcation {

	public static void main(String[] args) {
		SpringApplication.run(SourceReadApplillcation.class,args);
	}
}
  1. 这里传入启动类的class,然后调用SpringApplication的构造函数new一个实例,接着调用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);
}
public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
}

	
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
    
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //推断web应用类型;
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //设置初始化器,从META-INF/spring.factories读取ApplicationContextInitializer
    //配置的值,读取详情后续研究
	setInitializers((Collection) getSpringFactoriesInstances(
			ApplicationContextInitializer.class));
    //设置监听器,同上,读取ApplicationListener配置的值
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //设置应用main启动类
	this.mainApplicationClass = deduceMainApplicationClass();
}

负责启动SpringBoot的主要方法

public ConfigurableApplicationContext run(String... args) {
    //计时器,主要为了统计消耗时间
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
    
    //初始化应用上下文和异常报告集合
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    
    //设置java.awt.headless模式为true
	onfigureHeadlessProperty();
    
    //设置并启动META-INF/spring.factories下SpringApplicationRunListener配置的监听器
    //这里为EventPublishingRunListener,会通过反射调用其构造函数进行初始化
    //并将一开始设置的监听器保存到AbstractApplicationEventMulticaster的
    //内部类ListenerRetriever中,详情后续
	SpringApplicationRunListeners listeners = getRunListeners(args);
    //触发监听器开始启动事件
	listeners.starting();
	try {
        //初始化应用参数,例如启动设置的命令行参数等,可以通过这个类获取
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);
        //准备运行环境
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
				applicationArguments);
		configureIgnoreBeanInfo(environment);
        //打印banner
		Banner printedBanner = printBanner(environment);
		//创建上下文,Springboot默认为AnnotationConfigApplicationContext
		context = createApplicationContext();
        //准备异常报告
		exceptionReporters = getSpringFactoriesInstances(
				SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
        //准备上下文
		prepareContext(context, environment, listeners, applicationArguments,
				printedBanner);
        //刷新上下文
		refreshContext(context);
        //上下文刷新后置处理(空方法)
		afterRefresh(context, applicationArguments);
        //计时统计结束
	    stopWatch.stop();
        
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass)
					.logStarted(getApplicationLog(), stopWatch);
		}
        //触发启动完成事件
		listeners.started(context);
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}
	try {
        //触发运行事件
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

整个启动流程大体就是这样,先有一个整体的概念,其中实现细节很庞杂,后续逐一研究

posted @ 2019-07-08 12:07  NealRiver  阅读(258)  评论(0编辑  收藏  举报