SpringBoot运行流程源码分析------阶段二(run方法核心流程)

run方法核心流程

在分析和学习整个run方法之前,我们可以通过以下流程图来看下SpringApplication调用的run方法处理的核心操作包含哪些。
在这里插入图片描述
从上面的流程图中可以看出,SpringApplication在run方法中重点做了以下几步操作

  • 获取监听器和参数配置
  • 打印banner信息
  • 创建并初始化容器
  • 监听器发送通知
    除了以上核心操作,run方法运行过程中还设计启动时长统计,异常报告,启动日志,异常处理等辅助操作。
    对照流程图,我们再来整体看下入口run方法的源代码,核心部分的功能已通过注释的形式进行说明。
/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
   
		//创建stopWatch对象,用于统计run方法启动时长
		StopWatch stopWatch = new StopWatch();
		//启动统计
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		//配置headless属性
		configureHeadlessProperty();
		//获得SpringApplicationListener数组
		//该数组封装于SpringApplicationRunListeners对象的listeners中
		SpringApplicationRunListeners listeners = getRunListeners(args);
		//启动监听,遍历SpringApplicationRunListener数组每个元素,并执行
		listeners.starting();
		try {
   
			//创建ApplicationArguments对象
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			//加载属性配置,包括所有的配置属性(如application.properties中和外部的属性配置)
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			//打印banner
			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);
			//停止时长统计
			stopWatch.stop();
			//打印日东日志
			if (this.logStartupInfo) {
   
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			//通知监听器,容器启动完成
			listeners.started(context);
			//调用ApplicationRunner和CommandLineRunner的运行方法
			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;
	}

SpringApplicationRunListener监听器

监听器的加载与配置

SpringApplicationRunListeners可以理解为一个SpringApplicationRunListener的容器,它将SpringApplicationRunListener的集合以构造方法传入,并赋值给其listeners成员变量,然后提供了针对listeners成员变量的各种遍历操作方法,比如,遍历集合并调用对应的starting,started,running等方法。
SpringApplicationRunListeners的构造方法很简单,其源码如下:

private SpringApplicationRunListeners getRunListeners(String[] args) {
   
		//构造Class数组
		Class<?>[] types = new Class<?>[] {
    SpringApplication.class, String[].class };
		//调用SpringApplicationRunListeners构造方法
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

SpringApplicationRunListeners 构造方法的第二个参数便是SpringApplicationRunListener的集合,SpringApplication中调用构造方法时该参数是通过getSpringFactoriesInstances方法1获取的,代码如下:

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
   
		//获得类加载器
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		//加载META-INF/spring.factories中对应监听器的配置,并将结果存于Set中(去重)
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		//实例化监听器
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		//排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

通过方法名可知,getSpringFactoriesInstances是用来获取factories配置文件中的注册类,并进行实例化操作。SpringApplicationRunListener的注册配置位于spring-boot项目中的spring.factories文件内,SringBoot默认仅有一个监听器进行了注册,至于为什么会仅有一个,后面来说哈。

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

下面继续看createSpringFactoriesInstances方法的源码:

	@SuppressWarnings("unchecked")
	private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
   
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
   
			try {
   
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				//获取有参构造器
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
   
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

在上面的代码中,实例化监听器需要有一个默认的构造方法,且构造方法的参数为Class<?>[] parameterTypes。向上追踪该参数的来源,会发现该参数的1值为Class数组,数组的内容依次为SpringApplication.class和String[].class。也就是,SpringApplicationRunListener的实现类必须有默认的构造方法,且构造方法的参数必须依次为SpringApplication和String[]类型。

SpringApplicationRunListener源码解析

接口SpringApplicationRunListener是SpringApplication的run方法监听器。SpringApplicationRunListene提供了一系列的方法,用户可以通过回调这些方法,在启动各个流程时加入指定的逻辑处理。下面解释下该接口都定义了那些待实现的方法及功能。

/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

double_lifly

点喜欢就是最好的打赏!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值