SpringBoot源码分析之-启动流程分析二(run方法步骤介绍)

前言

上一篇:SpringBoot源码分析之-启动流程分析一(SpringApplication构造器)分析了SpringApplication的构造初始化,初始化主要设置加载类,项目类型(非web,servlet web,响应式web),上下文初始化器,监听器,程序主入口. 还介绍了一些方法的实现.
这篇主要分析run方法做了什么事情

run主要流程介绍

1.创建一个StopWatch,用于监控启动过程
2.设置程序为无显示模式
3.获取监听器SpringApplicationRunListener,用于启动过程的事件广播
4.广播启动事件(ApplicationStartingEvent)
5.环境准备 environment 广播
6.创建上下文
7.获取SpringBootExceptionReporter , (启动失败的异常信息日志)
8.准备上下文
9.刷新上下文
10.刷新上下文之后的一些扩展 (现在是空的,有需要自己可以重写)
11.输出启动的时间
12.广播启动成功事件
13. callRunners 执行自定义的业务代码(比如业务初始化)
13.广播运行成事件
	/**
	 * 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,用于监控启动过程
		StopWatch stopWatch = new StopWatch();
		//启动时间戳:纳秒
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		//设置了系统全局变量 java.awt.headless, true  
		//用于在缺失显示屏、鼠标或者键盘时的系统配置,也就是Web服务
		configureHeadlessProperty();
		
		//获取监听器SpringApplicationRunListener,用于启动时的事件广播
		SpringApplicationRunListeners listeners = getRunListeners(args);
		//广播ApplicationStartingEvent事件
		listeners.starting();
		try {
			// 参数封装
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 准备环境:命令行参数,系统参数,配置文件,外部配置文件,(非web/web/响应式web)项目环境
            //2、广播ApplicationEnvironmentPreparedEvent事件
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			// 设置系统变量spring.beaninfo.ignore, true
			configureIgnoreBeanInfo(environment);
			//打印banner
			Banner printedBanner = printBanner(environment);
			// 创建ConfigurableApplicationContext 应用上下文容器
			context = createApplicationContext();
			//创建SpringBootExceptionReporter, 启动异常后的相关处理
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			//准备容器
			//广播ApplicationEnvironmentPreparedEvent事件
			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;
	}

方法介绍

configureHeadlessProperty();

设置请求头

private void configureHeadlessProperty() {
		// private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
				System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

getRunListeners()

//获取EventPublishingRunListener实例

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}
	
	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

通过类路径下所有的 META-INF/spring.factories获取SpringApplicationRunListener的实现类,目前只有一个EventPublishingRunListener

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

SpringApplicationRunListener相关代码分析放在下一篇介绍

createApplicationContext()

根据构建SpringApplication是确定的项目类型, 创建不同上下文

	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);
	}

refreshContext(context);

刷新上下文, 就是初始化Spring项目. 具体行为后续博客再分析

afterRefresh(context, applicationArguments);

刷新上下文之后的一些扩展,现在是空方法

callRunners(context, applicationArguments);

业务相关初始化代码可以通过实现ApplicationRunner 或 CommandLineRunner来实现.

private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		//容器里获取ApplicationRunner实现bean
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		//获取CommandLineRunner
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		//排序
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}
	
	private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args);
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
		}
	}

	private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args.getSourceArgs());
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值