Spring Boot 启动流程源码分析(2)

前言:

前文我们宏观的分析了 Spring Boot 的启动流程,本篇将分析一下 SpringApplication#run 的重点步骤。

Spring Boot 系列文章传送门

Spring Boot 启动流程源码分析(2)

SpringApplication#run 方法源码解析

解析 SpringApplication#run 方法源码,Spring Boot 启动流程大概分为一下几点步骤,如下:

  • 获取监听器,启动监听。
  • 加载环境配置。
  • 创建应用程序上下文。
  • 准备上下文,各种初始化操作。
  • 刷新上下文,最终调用到 AbstractApplicationContext#refresh 方法,也就是 Spirng 容器启动。
  • 刷新后操作,模板方法,空实现。
java 复制代码
//org.springframework.boot.SpringApplication#run(java.lang.String...)
public ConfigurableApplicationContext run(String... args) {
	//计时器 记录启动耗时
	StopWatch stopWatch = new StopWatch();
	//启动开始
	stopWatch.start();
	//创建默认的引导上下文
	DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
	//可配置的应用程序上下文
	ConfigurableApplicationContext context = null;
	//java.awt.headless 是 J2SE 的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置 很多监控工具如jconsole 需要将该值设置为true 系统变量默认为true
	this.configureHeadlessProperty();
	//获取 SpringApplicationRunListener 实例数组 默认获取的是 EventPublishRunListener
	SpringApplicationRunListeners listeners = this.getRunListeners(args);
	//启动监听
	listeners.starting(bootstrapContext, this.mainApplicationClass);

	try {
		//创建 ApplicationArguments 默认应用程序参数 对象
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		//加载环境配置
		ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
		//忽略配置 bena 信息
		this.configureIgnoreBeanInfo(environment);
		//Banner 打印
		Banner printedBanner = this.printBanner(environment);
		//创建 应用程序上下文
		context = this.createApplicationContext();
		//设置应用程序启动
		context.setApplicationStartup(this.applicationStartup);
		//准备上下文 就是各种初始化错误
		this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
		//刷新上下文 最终调用到 AbstractApplicationContext#refresh 方法
		this.refreshContext(context);
		//刷新后操作 空实现
		this.afterRefresh(context, applicationArguments);
		//结束计时
		stopWatch.stop();
		if (this.logStartupInfo) {
			(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
		}
		//监听器启动
		listeners.started(context);
		//调用 ApplicationRunner 和 CommandLineRunner 
		this.callRunners(context, applicationArguments);
	} catch (Throwable var10) {
		//失败处理
		this.handleRunFailure(context, var10, listeners);
		throw new IllegalStateException(var10);
	}

	try {
		//通知监听器  Spring Boot 正在运行
		listeners.running(context);
		return context;
	} catch (Throwable var9) {
		//失败处理
		this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
		throw new IllegalStateException(var9);
	}
}

获取监听器

SpringApplication#getRunListeners 方法获取监听器,启动监听,SpringApplicationRunListeners 类中有一个监听器数组 listeners,获取监听器的源码前文在分析 SpringApplication 构造函数的时候已经分析过了,就是加载 class 下 META-INF/spring.factories 文件中 ApplicationListener 的实现类。

java 复制代码
//org.springframework.boot.SpringApplication#getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
	Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
	//创建一个 SpringApplicationRunListeners 对象 加载 class 下 META-INF/spring.factories 文件中 ApplicationListener 的实现类
	return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}

//org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
	//真正处理的方法
	return this.getSpringFactoriesInstances(type, new Class[0]);
}

//org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	//获取类加载器
	ClassLoader classLoader = this.getClassLoader();
	//获取所有类名 SpringFactoriesLoader.loadFactoryNames(type, classLoader) 重点关注一下
	//SpringFactoriesLoader.loadFactoryNames(type, classLoader) 就是根据接口名字 获取实现类的名称
	Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	//根据获取到的所有类名获取实例对象
	List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	//排序
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

启动监听器

SpringApplicationRunListeners#starting 启动监听器,其调用的是 EventPublishingRunListener#starting 方法,最终调用的是 SimpleApplicationEventMulticaster#multicastEvent 方法来发布监听事件。

java 复制代码
//org.springframework.boot.SpringApplicationRunListeners#starting
void starting() {
	//迭代遍历所有监听器
	Iterator var1 = this.listeners.iterator();

	while(var1.hasNext()) {
		SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
		//调用 事件发布运行监听器 EventPublishingRunListener#starting 方法
		listener.starting();
	}

}

//org.springframework.boot.context.event.EventPublishingRunListener#starting
public void starting() {
	//调用 简单应用程序事件多播器 SimpleApplicationEventMulticaster#multicastEvent 多播事件 也就是启动监听事件
	this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}


//org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent)
public void multicastEvent(ApplicationEvent event) {
	//调用 简单应用程序事件多播器 SimpleApplicationEventMulticaster#multicastEvent
	this.multicastEvent(event, this.resolveDefaultEventType(event));
}


//org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
	//解析事件类型
	ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
	//获取线程池
	Executor executor = this.getTaskExecutor();
	//迭代遍历监听器
	Iterator var5 = this.getApplicationListeners(event, type).iterator();

	while(var5.hasNext()) {
		//监听器
		ApplicationListener<?> listener = (ApplicationListener)var5.next();
		if (executor != null) {
			//线程池异步发送监听事件
			executor.execute(() -> {
				this.invokeListener(listener, event);
			});
		} else {
			//同步发送监听事件
			this.invokeListener(listener, event);
		}
	}

}

加载环境配置

SpringApplication#prepareEnvironment 方法就是获取一个环境对象,Environment 接口提供了三种实现,标准环境 StandardEnvironment、web 应用环境 StandardServletEnvironment、响应式 web 应用环境 StandardReactiveWebEnvironment。

java 复制代码
//org.springframework.boot.SpringApplication#prepareEnvironment 
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
	//获取或创建 配置环境对象
	ConfigurableEnvironment environment = this.getOrCreateEnvironment();
	//配置环境
	this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach((Environment)environment);
	//发布环境已准备事件
	listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
	DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
	this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
	//环境配置绑定到 Spring 应用程序上
	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.SpringApplication#getOrCreateEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
	//环境为空判断
	if (this.environment != null) {
		//不为空 直接返回
		return this.environment;
	} else {
		//为空 根据项目类型创建不同的环境对象
		switch(this.webApplicationType) {
		case SERVLET:
			//响应式 web 应用环境
			return new StandardServletEnvironment();
		case REACTIVE:
			//web 应用环境
			return new StandardReactiveWebEnvironment();
		default:
			//标准环境
			return new StandardEnvironment();
		}
	}
}

创建应用程序上下文

创建容器会调用 ApplicationContextFactory#create 方法,根据项目类型去创建容器,项目类型前文已经多次赘述,这里不再分析了。

java 复制代码
protected ConfigurableApplicationContext createApplicationContext() {
	return this.applicationContextFactory.create(this.webApplicationType);
}

package org.springframework.boot;

import java.util.function.Supplier;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

@FunctionalInterface
public interface ApplicationContextFactory {
    ApplicationContextFactory DEFAULT = (webApplicationType) -> {
        try {
            switch(webApplicationType) {
            case SERVLET:
                return new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            default:
                return new AnnotationConfigApplicationContext();
            }
        } catch (Exception var2) {
            throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
        }
    };

    ConfigurableApplicationContext create(WebApplicationType webApplicationType);

    static ApplicationContextFactory ofContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {
        return of(() -> {
            return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
        });
    }

    static ApplicationContextFactory of(Supplier<ConfigurableApplicationContext> supplier) {
        return (webApplicationType) -> {
            return (ConfigurableApplicationContext)supplier.get();
        };
    }
}

准备上下文,完成各种初始化操作

SpringApplication#prepareContext 方法主要是做一些容器刷新之前的动作,完成各类初始化动作,其中有一个比较核心的操作,把启动类注入容器,为后续开启自动化配置奠定了基础。

java 复制代码
//org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	//设置上下文环境
	context.setEnvironment(environment);
	//执行上下文后处理
	this.postProcessApplicationContext(context);
	//执行 ApplicationContextInitializer
	this.applyInitializers(context);
	//发布上下文准备好的监听事件
	listeners.contextPrepared(context);
	//关闭引导上下文
	bootstrapContext.close(context);
	if (this.logStartupInfo) {
		this.logStartupInfo(context.getParent() == null);
		this.logStartupProfileInfo(context);
	}
	//获取 ApplicationContextInitializer 
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	//注册单例bean springApplicationArguments  容器指定的参数封装成 bean  注入容器
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		//将 Banner 封装成 bean 注入到容器中
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	//是否是 DefaultListableBeanFactory 类型的容器
	if (beanFactory instanceof DefaultListableBeanFactory) {
		//是 强行覆盖
		((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	//是否懒加载
	if (this.lazyInitialization) {
		//加 懒加载 beanFactory 处理器
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	//获取启动类指定的参数
	Set<Object> sources = this.getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	//加载启动类 将启动类注入容器
	this.load(context, sources.toArray(new Object[0]));
	//发布容器加载完成事件
	listeners.contextLoaded(context);
}

刷新上下文

刷新上下文,最终调用到 AbstractApplicationContext#refresh 方法,也就是 Spirng 容器启动的核心方法。

AbstractApplicationContext#refresh 方法传送门:

深入理解 Spring IOC 底层实现机制(refresh 方法源码分析)

java 复制代码
//org.springframework.boot.SpringApplication#refreshContext
private void refreshContext(ConfigurableApplicationContext context) {
	//判斷是否注册关闭钩子函数 默认注册
	if (this.registerShutdownHook) {
		try {
			//注册关闭钩子函数
			context.registerShutdownHook();
		} catch (AccessControlException var3) {
		}
	}
	//继续调用 refresh 方法
	this.refresh((ApplicationContext)context);
}


//org.springframework.boot.SpringApplication#refresh(org.springframework.context.ApplicationContext)
@Deprecated
protected void refresh(ApplicationContext applicationContext) {
	Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
	//继续调用 refresh 方法
	this.refresh((ConfigurableApplicationContext)applicationContext);
}


//org.springframework.boot.SpringApplication#refresh(org.springframework.context.ConfigurableApplicationContext)
protected void refresh(ConfigurableApplicationContext applicationContext) {
	//调用 AbstractApplicationContext#refresh 方法
	applicationContext.refresh();
}


//org.springframework.context.support.AbstractApplicationContext#refresh
//IOC 核心方法
public void refresh() throws BeansException, IllegalStateException {
	//防止 启动和销毁并发执行
	synchronized(this.startupShutdownMonitor) {
		//启动步骤记录
		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
		//刷新准备工作
		this.prepareRefresh();
		//创建 beanFactory 将配置文件解析为 beandefiniton 对象 注册到 beanFactory 中
		//ConfigurableListableBeanFactory是一个接口 真正干活的是 DefaultListableBeanFactory
		ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
		//beanFactory 预处理 主要是设置 beanFactory 类加载器及忽略一些自动装配 设置一些默认bena
		this.prepareBeanFactory(beanFactory);

		try {
			//beanFactory 后置处理 准备完成后需要做的事情 默认是空实现 是一个扩展点 可以子类去实现
			this.postProcessBeanFactory(beanFactory);
			//启动 bean post-process 步骤记录
			StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
			//回调 beanFactory 后置处理器 beanFactoryPostProcessors 的 postProcessorsBeanFactory 方法   (也可以说是激活 beanFactoryPostPorcess)
			this.invokeBeanFactoryPostProcessors(beanFactory);
			//注册beanPostProcessors bean 后置处理器(注意上面是beanFactory后置处理器) 在bean 初始化之前之后执行
			this.registerBeanPostProcessors(beanFactory);
			//bean 后置处理器步骤结束
			beanPostProcess.end();
			//初始化国际化资源
			this.initMessageSource();
			//初始化应用程序事件多播器
			this.initApplicationEventMulticaster();
			//默认是空方法 可以子类重写  自己进行扩展
			this.onRefresh();
			//注册监听器
			this.registerListeners();
			//初始化单例bean(非懒加载)
			this.finishBeanFactoryInitialization(beanFactory);
			//完成后刷新 包括清空资源 发布事件等
			this.finishRefresh();
		} catch (BeansException var10) {
			if (this.logger.isWarnEnabled()) {
				this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
			}
			//销毁ben
			this.destroyBeans();
			//取消刷新
			this.cancelRefresh(var10);
			throw var10;
		} finally {
			this.resetCommonCaches();
			contextRefresh.end();
		}

	}
}

刷新后操作

SpringApplication#afterRefresh 方法是个模板方法,默认空实现,可以自己去扩展。

java 复制代码
//org.springframework.boot.SpringApplication#afterRefresh
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	
}

SpringApplication#callRunners 方法分析

SpringApplication#callRunners 调用 ApplicationRunner 和 CommandLineRunner 的实现类,也就是平时我们自定义一些实现了 Runner 接口的类,在项目启动时候执行。

java 复制代码
//org.springframework.boot.SpringApplication#callRunners
private void callRunners(ApplicationContext context, ApplicationArguments args) {
	//存储所有的 Runner
	List<Object> runners = new ArrayList();
	//获取所有的 ApplicationRunner 的实现类 加入到 runners 中
	runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
	//获取所有的 CommandLineRunner 的实现类 加入到 runners 中
	runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
	//对所有 Runner 排序
	AnnotationAwareOrderComparator.sort(runners);
	//迭代遍历
	Iterator var4 = (new LinkedHashSet(runners)).iterator();

	while(var4.hasNext()) {
		Object runner = var4.next();
		//ApplicationRunner 类型 runner
		if (runner instanceof ApplicationRunner) {
			//调用 runner 的 run 方法
			this.callRunner((ApplicationRunner)runner, args);
		}
		//CommandLineRunner 类型 runner
		if (runner instanceof CommandLineRunner) {
			//调用 runner 的 run 方法
			this.callRunner((CommandLineRunner)runner, args);
		}
	}

}


//org.springframework.boot.SpringApplication#callRunner(org.springframework.boot.CommandLineRunner, org.springframework.boot.ApplicationArguments)
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
	try {
		//执行 runner 的 run 方法 也就是我们自己定义的 runner 的业务方法
		runner.run(args.getSourceArgs());
	} catch (Exception var4) {
		throw new IllegalStateException("Failed to execute CommandLineRunner", var4);
	}
}

至此,Spring Boot 的启动流程分析完毕,希望可以帮助到有需要的小伙伴。

如有不正确的地方请各位指出纠正。

相关推荐
是小崔啊1 小时前
开源轮子 - EasyExcel02(深入实践)
java·开源·excel
myNameGL2 小时前
linux安装idea
java·ide·intellij-idea
青春男大2 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
HaiFan.2 小时前
SpringBoot 事务
java·数据库·spring boot·sql·mysql
2401_882727572 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·前端框架
我要学编程(ಥ_ಥ)2 小时前
一文详解“二叉树中的深搜“在算法中的应用
java·数据结构·算法·leetcode·深度优先
music0ant2 小时前
Idea 添加tomcat 并发布到tomcat
java·tomcat·intellij-idea
计算机徐师兄3 小时前
Java基于SSM框架的无中介租房系统小程序【附源码、文档】
java·微信小程序·小程序·无中介租房系统小程序·java无中介租房系统小程序·无中介租房微信小程序
源码哥_博纳软云3 小时前
JAVA智慧养老养老护理帮忙代办陪诊陪护小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
追逐时光者3 小时前
.NET 在 Visual Studio 中的高效编程技巧集
后端·.net·visual studio