Springboot启动流程简述

Springboot提高了开发效率,简化了配置,往往使用一些注解就可以使项目跑起来,下面理一下Springboot的启动流程。Springboot版本:2.2.4.RELEASE

以下是一个常见的Springboot启动程序。

main方法里调用了SpringbootApplication的run方法。让我们点进去run方法,看看做了什么。

可以看到new了一个SpringApplication对象,然后调用其run方法。我们分两步来说即new SpringApplication(primarySources) 和 run(args).

实例化SpringApplication[new SpringApplication(primarySources)]

 从上图中可以看到主要是设置一些参数,其中主要重点讲一下这四块

// 获取 webApplicationType 有 REACTIVE 和 SERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置ApplicationContextInitializer
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置ApplicationListener
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 获取MainApplication的Class
this.mainApplicationClass = this.deduceMainApplicationClass();

这里我们重点说this.getSpringFactoriesInstances()这个方法,这个其实使获取META-INF\spring.factories中的配置。

以this.getSpringFactoriesInstances(ApplicationContextInitializer.class)为例。

 以上是获取到的实现类,点进去SpringFactoriesLoader.loadFactoryNames(type, classLoader)可以发现是读取的"META-INF/spring.factories"配置文件,如下

 然后通过反射实例化这些instances.

SpringApplication的run方法

public ConfigurableApplicationContext run(String... args) {
    // 创建一个StopWatch并执行start方法,主要记录任务的执行时间
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
	this.configureHeadlessProperty();
    // 获取监听器(SpringApplicationRunListener实现类)类似以上,也是调用this.getSpringFactoriesInstances().
    // 主要发布SpringApplicationEvent
	SpringApplicationRunListeners listeners = this.getRunListeners(args);
    // 监听器启动
	listeners.starting();

	Collection exceptionReporters;
	try {
        // 把输入参数转成DefaultApplicationArguments类
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 准备环境,在这里读取配置文件(application.properties application.yml)
		ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
		this.configureIgnoreBeanInfo(environment);
        // 读取打印banner
		Banner printedBanner = this.printBanner(environment);
        // 创建应用程序上下文 此处创建了beanfactory
		context = this.createApplicationContext();
        // 获取SpringBootExceptionReporter的实现类对象
		exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
        // 准备上下文
		this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 刷新上下文
		this.refreshContext(context);
		this.afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
		}

        // 启动完成通知
		listeners.started(context);
		this.callRunners(context, applicationArguments);
	} catch (Throwable var10) {
		this.handleRunFailure(context, var10, exceptionReporters, listeners);
		throw new IllegalStateException(var10);
	}

	try {
		listeners.running(context);
		return context;
	} catch (Throwable var9) {
		this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
		throw new IllegalStateException(var9);
	}
}

准备环境 this.prepareEnvironment(listeners, applicationArguments)

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    // 根据webApplicationType返回ConfigurableEnvironment实例
	ConfigurableEnvironment environment = this.getOrCreateEnvironment();
	this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach((Environment)environment);
    // 这里会创建一个ApplicationEnvironmentPreparedEvent类型的事件,并广播出去
    // 之前获取的监听会监听到这个事件,并调用onApplicationEvent进行相应的处理
    // ConfigFileApplicationListener监听器会加载配置文件(application.yml application.properties)
	listeners.environmentPrepared((ConfigurableEnvironment)environment);
	this.bindToSpringApplication((ConfigurableEnvironment)environment);
	if (!this.isCustomEnvironment) {
		environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
	}

	ConfigurationPropertySources.attach((Environment)environment);
	return (ConfigurableEnvironment)environment;
}

这里讲一下加载配置文件的流程。

 涉及到的监听器和后置处理器如下

org.springframework.boot.context.config.ConfigFileApplicationListener

org.springframework.boot.env.YamlPropertySourceLoader

org.springframework.boot.env.PropertiesPropertySourceLoader

有兴趣的同学可以调试一下

创建上下文 this.createApplicationContext()

根据webApplicationType创建ConfigurableApplicationContext实例

 

准备上下文 this.prepareContext()

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    // 设置上下文的配置环境
	context.setEnvironment(environment);
    // 上下文后置处理
	this.postProcessApplicationContext(context);
    // 
	this.applyInitializers(context);
    // 以上为上下文准备阶段
    // 以下为上下文加载阶段
    // //通知监听器 context 准备完成,发布ApplicationContextInitializedEvent事件
	listeners.contextPrepared(context);
    // 打印启动日志和profile
	if (this.logStartupInfo) {
		this.logStartupInfo(context.getParent() == null);
		this.logStartupProfileInfo(context);
	}

    // 获得 beanFactory 并注册单例
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
        // 注册打印banner对象
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}

    // 设置是否允许覆盖
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}

    // 如果延迟加载,在上下文添加处理器
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}

	Set<Object> sources = this.getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
    // 创建BeanDefinitionLoader,然后在BeanDefinitionLoader中初始化了各种读取器和扫描器
	this.load(context, sources.toArray(new Object[0]));
    // 发布ApplicationPreparedEvent事件,通知监听器 context 加载完成
	listeners.contextLoaded(context);
}

刷新上下文 this.refreshContext(context);

public void refresh() throws BeansException, IllegalStateException {
	synchronized(this.startupShutdownMonitor) {
        // 为应用上下文的刷新做准备--设置时间、记录刷新日志、验证属性
		this.prepareRefresh();
        // 让子类刷新内部的bean factory
		ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        // 准备在这个应用上下文中使用的bean factory
		this.prepareBeanFactory(beanFactory);

		try {
            // bean factory 后置处理
			this.postProcessBeanFactory(beanFactory);
            // 调用应用上下文中作为bean注册的工厂处理器
			this.invokeBeanFactoryPostProcessors(beanFactory);
            // 注册创建bean的bean处理器,以增强 bean
			this.registerBeanPostProcessors(beanFactory);
            // 初始化消息源
			this.initMessageSource();
            // 初始化事件广播
			this.initApplicationEventMulticaster();
            // 此处定义特别的bean创建,一般是服务器有关或个性化对象
            // 子这里会创建默认tomcat服务器
			this.onRefresh();
            // 注册监听器bean
			this.registerListeners();
            // 实例化所有的单例bean
			this.finishBeanFactoryInitialization(beanFactory);
            // 发布相应的事件
			this.finishRefresh();
		} catch (BeansException var9) {
			if (this.logger.isWarnEnabled()) {
				this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
			}

			this.destroyBeans();
			this.cancelRefresh(var9);
			throw var9;
		} finally {
			this.resetCommonCaches();
		}

	}
}

通知监听者-启动程序完成

listeners.started(context);
listeners.running(context);

void started(ConfigurableApplicationContext context) {
	Iterator var2 = this.listeners.iterator();

	while(var2.hasNext()) {
		SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
		listener.started(context);
	}

}

void running(ConfigurableApplicationContext context) {
	Iterator var2 = this.listeners.iterator();

	while(var2.hasNext()) {
		SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
		listener.running(context);
	}

}

// 发布ApplicationStartedEvent事件
public void started(ConfigurableApplicationContext context) {
	context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}

// 发布ApplicationReadyEvent事件
public void running(ConfigurableApplicationContext context) {
	context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}

以上为自己理解,如有错误,请指出。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值