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 的启动流程分析完毕,希望可以帮助到有需要的小伙伴。

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

相关推荐
EyeDropLyq几秒前
线上事故处理记录
后端·架构
云朵大王8 分钟前
SQL 视图与事务知识点详解及练习题
java·大数据·数据库
我爱Jack31 分钟前
深入解析 LinkedList
java·开发语言
一线大码1 小时前
Gradle 高级篇之构建多模块项目的方法
spring boot·gradle·intellij idea
27669582922 小时前
tiktok 弹幕 逆向分析
java·python·tiktok·tiktok弹幕·tiktok弹幕逆向分析·a-bogus·x-gnarly
用户40315986396632 小时前
多窗口事件分发系统
java·算法
用户40315986396632 小时前
ARP 缓存与报文转发模拟
java·算法
小林ixn2 小时前
大一新手小白跟黑马学习的第一个图形化项目:拼图小游戏(java)
java
nbsaas-boot2 小时前
Go语言生态成熟度分析:为何Go还无法像Java那样实现注解式框架?
java·开发语言·golang
MarkGosling2 小时前
【开源项目】网络诊断告别命令行!NetSonar:开源多协议网络诊断利器
运维·后端·自动化运维