spring boot 使用系列二(启动流程)

spring boot 使用系列一中我们介绍了最简单使用spring boot的方法。我们看到Spring boot应用的核心启动代码如下:

@SpringBootApplication
public class BootApplication {

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

从代码中,我们看到了两个新面孔:@SpringBootApplication 和 SpringApplication。这两个是spring boot的两个核心点,所以我们都会分析。

本文,我们从SpringApplication.run(BootApplication.class, args)入口分析spring boot运行过程中信息:
后续spring boot 使用系列三,我们来分析注解@SpringBootApplication。

启动流程

SpringApplication默认启动流程

  1. 根据classpath,创建相关的ApplicationContext
  2. 注册一个CommandLinePropertySource把命令行参数显示为Spring的properties
  3. 刷新ApplicationContext,加载所有的singleton bean
  4. 触发所有的CommandLineRunner实例
    一般场景使用SpringApplication.run(Class,String[])就可以了。

SpringApplication能够加载多种不同的source

  • AnnotatedBeanDefinitionReader加载全限定的类名。
  • XmlBeanDefinitionReader加载的xml文件,或者GroovyBeanDefinitionReader加载groovy脚本
  • ClassPathBeanDefinitionScanner扫描的包

SpringApplication的核心run流程:

1、构建SpringApplication对象:
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();
	}
  • 通过classpath推断web的类型。具体逻辑比较简单。
  • 设置ApplicationContextInitializer: 扫描classpath下面 "META-INF/spring.factories"下的文件,加载其中ApplicationContextInitializer指定的类
  • 设置ApplicationListener:扫描classpath下面 "META-INF/spring.factories"下的文件,加载其中ApplicationListener指定的类
  • 通过堆栈信息推断出主应用程序类
2、SpringApplication的run方法:

去除掉无用的日志、watch代码、异常处理等代码

public ConfigurableApplicationContext run(String... args) {
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	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);
	listeners.started(context);
	callRunners(context, applicationArguments);
	listeners.running(context);
	return context;
}
  • 配置java.awt.headless属性,默认为true
  • 加载配置的所有SpringApplicationRunListener实例。并聚合为 SpringApplicationRunListeners实例
  • 准备好Environment。并通过SpringApplicationRunListeners调用所有SpringApplicationRunListener实例的environmentPrepared方法。
  • 创建ConfigurableApplicationContext实例
  • 加载配置的所有SpringBootExceptionReporter实例
  • 配置好ConfigurableApplicationContext。
    1. 设置ConfigurableApplicationContext的environment属性
    2. 应用相关的post处理程序
    3. 调用所有的ApplicationContextInitializer实例的initialize方法
    4. 通过SpringApplicationRunListeners调用所有SpringApplicationRunListener实例的 contextPrepared方法。
    5. 增加一些spring boot特有的singleton beans,例如springApplicationArguments,springBootBanner,LazyInitializationBeanFactoryPostProcessor等
    6. 加载所有的source及导入相应的bean,并通过SpringApplicationRunListeners调用所有SpringApplicationRunListener实例的contextLoaded方法。
  • 刷新context。调用给你context的refresh方法。这个过程后复杂,后续专门文章分析
  • 通过SpringApplicationRunListeners调用所有SpringApplicationRunListener实例的started方法。
  • 调用所有的ApplicationRunner和CommandLineRunner的实例的run方法。如果前面方法有任何异常,都通过SpringApplicationRunListeners调用所有SpringApplicationRunListener实例的failed方法进行通知。并调用所有SpringBootExceptionReporter实例的reportException方法。
  • 通过SpringApplicationRunListeners调用所有SpringApplicationRunListener实例的running方法。

扩展点

1、SpringApplication的各种set方法,可以根据自己的需要设置

 public static void main(String[] args) {
    SpringApplication application = new SpringApplication(MyApplication.class);
    // ... customize application settings here. 各种设置可以配置SpringApplication的部分行为。
    application.run(args)
 }

2、通过SpringApplicationRunListener扩展需求

可以在SpringApplication的run过程中增加自定义的操作。当到达指定的流程,会触发我们自定义的操作。

3、通过扩展SpringApplication扩展一些新的功能或者重写启动流程

这个扩展需要特别小心,许多高级功能可以扩展。protected方法可以重写,再定义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值