SpringBoot 源码解析2:启动流程1

SpringBoot 源码解析2:启动流程1

    • 1.启动方式
    • 2.@SpringBootApplication
    • 3.SpringApplication
      • 3.1 构造器SpringApplication
      • 3.2 SpringApplication#run
    • 3.3 SpringApplication#run 中关键方法
      • 3.1 SpringApplication#prepareEnvironment
      • 3.2 SpringApplication#prepareContext
      • 3.3 SpringApplication#createApplicationContext
      • 3.4 SpringApplication#prepareContext
      • 3.5 SpringApplication#refreshContext
      • 3.6 SpringApplicationRunListeners#started
      • 3.7 callRunners
      • 3.8 SpringApplicationRunListeners#running

1.启动方式

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

SpringBoot启动方式,这里就不多做说明了

2.@SpringBootApplication

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
	xxxxx
}
  1. 可以看到SpringBootApplication注解由三个注解标注,@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。
  2. 简要说明一下这三个注解的作用:
    2.1. SpringBootConfiguration由Configuration标注,而Configuration又是由Component标注,Component表明这个类要被Spring管理。同时Configuration注解还能对当前类进行代理。
    2.2. EnableAutoConfiguration是由@Import注解所标注,而Import注解的作用是告诉Spring容器需要注入哪些bean。
    2.3. ComponentScan是用来配置扫描Component资源的策略,包含策略和剔除策略,剔除策略优先及高。

3.SpringApplication

3.1 构造器SpringApplication

@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));
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}
  1. 参数说明:resourceLoader写死null,primarySources为启动类MyApplication。
  2. 通过classLoader判断当前的WebApplicationType,这里返回的是WebApplicationType.SERVLET。
  3. 从spring.factories文件中拿到ApplicationContextInitializer和ApplicationListener。spring.factories文件解析可参考 SpringBoot 基础概念:SpringApplication#getSpringFactoriesInstances
  4. 推断出主类,通过RuntimeException的栈帧信息找到第一个"main"方法所属的类,也就是MyApplication。

3.2 SpringApplication#run

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);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}
  1. 这是SpringBoot真正启动的总流程。
  2. 从spring.factories文件中获取SpringApplicationRunListener对应的类,通过参数类型为SpringApplication.class, String[].class的构造器实例化,其中值为当前的SpringApplication对象和启动参数args,封装在SpringApplicationRunListeners里。其实是实例化了EventPublishingRunListener,从名字上可知,它是用来分发事件的。
    SpringBoot 源码解析2:启动流程1_第1张图片
  3. 调用SpringApplicationRunListeners#starting发布"正在启动"事件,事件为ApplicationStartingEvent。
  4. prepareEnvironment方法发布"环境准备"事件,由ConfigFileApplicationListener监听,然后解析配置文件(如yml、bootstrap、properties、xml等),将解析的信息存放到Environment里面。
  5. printBanner方法打印banner
  6. createApplicationContext创建ApplicationContext,判断的依据是webApplicationType。由于是Servlet类型的,创建的是AnnotationConfigServletWebServerApplicationContext。
  7. 获取异常报告事件监听器,在catch到异常监听failed。
  8. 准备applicationContext
  9. refreshContext(context)刷新容器
  10. listeners.started(context) 发布"已启动"事件
  11. 调用ApplicationRunner和CommandLineRunner
  12. listeners.running发送"running事件"

3.3 SpringApplication#run 中关键方法

3.1 SpringApplication#prepareEnvironment

3.2 SpringApplication#prepareContext

3.3 SpringApplication#createApplicationContext

3.4 SpringApplication#prepareContext

3.5 SpringApplication#refreshContext

3.6 SpringApplicationRunListeners#started

3.7 callRunners

3.8 SpringApplicationRunListeners#running

你可能感兴趣的:(spring,boot,后端,java)