SpringBoot源码解析

163 阅读2分钟

Spring Boot 是由 Pivotal 团队提供的全新框架,用来简化新 Spring 应用的初始搭建以及开发过程。 使用版本:2.3.0

Spring Boot特点:

1、降低开发复杂度
2、开箱即用,提过了各种默认配置简化项目配置
3、内嵌web容器

核心注解:

@SpringBootApplication 由以下三种组成:
@SpringBootConfiguration:配置文件
@EnableAutoConfiguration:打开自动配置功能
@ComponentScan:spring组件扫描

在读源码之前需要理解一个概念什么是SPI?

SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。

Spring Boot启动流程

1、创建SpringApplication对象,通过SPI机制加载applicationContextInitializer
2、调用run方法获取并启动监听器,准备环境environment,加载应用上下文applicationContext
3、创建spring容器,刷新容器,实例化bean

源码分析

1、初始化SpringAppliction时会区分当前应用程序是哪种环境:REACTIVE|NONE|SERVLET

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		//设置servlet环境
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		//获取ApplicationContextInitializer,首次加载META-INF/spring.factories中的类的名称
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//获取监听器,从spring.factories文件读取ApplicationListener类并初始化监听器对象
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

2、调用run方法,获取并启动监听器,准备环境environment,加载应用上下文applicationContext

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		//获取并启动监听器
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			//创建容器环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			//创建应用程序上下文
			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);
		}
		--------
		return context;
	}