2启动过程源码

目录

1SpringApplication初始化

2run()

2.1获取run方法的监听器EventPublishingRunListener

2.2准备环境:prepareEnvironment()

2.3创建容器:createApplicationContext()

2.4获取SpringBootExceptionReporter

2.5准备容器prepareContext()

2.6refresh


1SpringApplication初始化

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //判断web环境:NONE、SERVLET、REACTIVE
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //从Spring.factories加载Initializer
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
        //从Spring.factories加载监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //获取主类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

2run()

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();

        /第一步:获取run方法的监听器EventPublishingRunListener,负责发布run方法中的事件
	SpringApplicationRunListeners listeners = getRunListeners(args);

        /发布starting事件
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
				args);
                /第二步:构造容器环境
		ConfigurableEnvironment environment = prepareEnvironment(listeners,
				applicationArguments);
                /设置需要忽略的bean
		configureIgnoreBeanInfo(environment);
                /打印banner
		Banner printedBanner = printBanner(environment);
                /第三步:创建容器
		context = createApplicationContext();
                /第四步:实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
		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;
}

2.1获取run方法的监听器EventPublishingRunListener

从spring.factories获取SpringApplicationRunListener的实现类EventPublishingRunListener,负责发布run方法中的事件,在run方法执行过程中触发监听器执行相应逻辑。

EventPublishingRunListener通过持有SimpleApplicationEventMulticaster对象,广播事件,遍历监听器执行相应方法。

public interface SpringApplicationRunListener {

	void starting();

	void environmentPrepared(ConfigurableEnvironment environment);

	void contextPrepared(ConfigurableApplicationContext context);

	void contextLoaded(ConfigurableApplicationContext context);

	void started(ConfigurableApplicationContext context);

	void running(ConfigurableApplicationContext context);

	void failed(ConfigurableApplicationContext context, Throwable exception);

}

2.2准备环境:prepareEnvironment()

加载外部化配置资源到environment,包括命令行参数、servletConfigInitParams、servletContextInitParams、systemProperties、sytemEnvironment、random、application.yml(.yaml/.xml/.properties)等;初始化日志系统。

2.3创建容器:createApplicationContext()

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

根据webApplicationType进行判断,创建对应类型容器。

2.4获取SpringBootExceptionReporter

从spring.factories获取,用来支持报告关于启动的错误

该类主要是在项目启动失败之后,打印log

2.5准备容器prepareContext()

这一步主要是在refresh()之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		//设置容器环境,包括各种变量
		context.setEnvironment(environment);
		//执行容器后置处理
		postProcessApplicationContext(context);
		//执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例)
		applyInitializers(context);
		//发送容器已经准备好的事件,通知各监听器
		listeners.contextPrepared(context);
		//打印log
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		//注册启动参数bean,这里将容器指定的参数封装成bean,注入容器
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		//设置banner
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}
		// Load the sources
		//获取我们的启动类指定的参数,可以是多个
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		//加载我们的启动类,将启动类注入容器
		load(context, sources.toArray(new Object[0]));
		//发布容器已加载事件。
		listeners.contextLoaded(context);
	}

 applyInitializers(context):

ApplicationContextInitializer是Spring框架原有的概念, 这个类的主要目的就是在 ConfigurableApplicationContext类型(或者子类型)的ApplicationContext做refresh之前,允许我们 对ConfigurableApplicationContext的实例做进一步的设置或者处理(加入beanFactoryPostProcessor)。

举例:

context.addBeanFactoryPostProcessor( new ConfigurationWarningsPostProcessor(getChecks()));

load(context, sources.toArray(new Object[0])):

这里会将我们的启动类加载到spring容器beanDefinitionMap中,为后续springBoot 自动化配置奠定基础,springBoot为我们提供的各种注解配置也与此有关。

2.6refresh

参考spring文章中的源码分析

 

参考:

SpringBoot2 | SpringBoot启动流程源码分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值