SpringBoot启动过程分析之SpringApplication的run方法解析

前言

SpringApplication是一个类,提供一些便利的功能,引导Spring的程序进行启动

Spring Boot 的入口类

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

做过 Spring Boot 项目的都知道,上面是 Spring Boot 最简单通用的入口类。入口类的要求是最顶层包下面第一个含有 main 方法的类,使用注解 @SpringBootApplication 来启用 Spring Boot 特性,使用 SpringApplication.run 方法来启动 Spring Boot 项目。

来看一下这个类的run方法调用关系源码:

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
}
	
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
}

这里有2个核心1个是SpringApplication的创建,另一个是其run方法的调用。本文重点研究run方法的调用

一、SpringApplication方法run源码概括

public class SpringApplication {

		public ConfigurableApplicationContext run(String... args) {
		        // 1、创建并启动计时监控类
				StopWatch stopWatch = new StopWatch();
				stopWatch.start();
				// 2、初始化应用上下文和异常报告集合
				ConfigurableApplicationContext context = null;
				Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
				 // 3、设置系统属性 `java.awt.headless` 的值,默认值为:true 开启headless模式
				configureHeadlessProperty();
				// 4、创建所有 Spring 运行监听器并发布应用启动事件
				SpringApplicationRunListeners listeners = getRunListeners(args);
				listeners.starting();
				try {
				    // 5、初始化默认应用参数类
					ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
					// 6、根据运行监听器和应用参数来准备 Spring 环境
					ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
					//配置是否忽略beanInfo
					configureIgnoreBeanInfo(environment);
					// 7、创建 Banner 打印类
					Banner printedBanner = printBanner(environment);
					// 8、创建应用上下文
					context = createApplicationContext();
					// 9、准备异常报告器
					exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
					// 10、准备应用上下文
					prepareContext(context, environment, listeners, applicationArguments, printedBanner);
					 // 11、刷新应用上下文
					refreshContext(context);
					// 12、应用上下文刷新后置处理
					afterRefresh(context, applicationArguments);
					// 13、停止计时监控类
					stopWatch.stop();
					// 14、输出日志记录执行主类名、时间信息
					if (this.logStartupInfo) {
						new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
					}
					 // 15、发布应用上下文启动完成事件
					listeners.started(context);
					// 16、执行所有 Runner 运行器
					callRunners(context, applicationArguments);
				}
				catch (Throwable ex) {
					handleRunFailure(context, ex, exceptionReporters, listeners);
					throw new IllegalStateException(ex);
				}
		
				try {
				    // 17、发布应用上下文就绪事件
					listeners.running(context);
				}
				catch (Throwable ex) {
					handleRunFailure(context, ex, exceptionReporters, null);
					throw new IllegalStateException(ex);
				}
				return context;
			}
}
3、设置系统属性 java.awt.headless 的值
public class SpringApplication {

	private void configureHeadlessProperty() {
	       //给属性java.awt.headless设置为true
			System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
		}
}

其实是想设置该应用程序,即使没有检测到显示器,也允许其启动.对于服务器来说,是不需要显示器的,所以要这样设置.

4、创建所有 Spring 运行监听器并发布应用启动事件
//SpringApplicationRunListeners listeners = getRunListeners(args);
//listeners.starting();

public class SpringApplication {

	private SpringApplicationRunListeners getRunListeners(String[] args) {
			Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
			return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
		}
		
	void starting() {
			for (SpringApplicationRunListener listener : this.listeners) {
				listener.starting();
			}
		}
}
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

5、初始化默认应用参数类

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

6、根据运行监听器和应用参数来准备 Spring 环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
		// 根据webApplicationType创建Environment创建就会读取:java环境变量和系统环境变量
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		//将命令行参数读取环境变量中
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		//将@PropertieSource的配置信息放在第一位,因为读取配置文件@PropertieSource优先级是最低的
		ConfigurationPropertySources.attach(environment);
		//发布了ApplicationEnvironmentPreparedEvent的监听,读取全局文件
		listeners.environmentPrepared(environment);
		//将所有spring.main开头的配置信息绑定SpringApplication
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		//更新PropertieSource
		ConfigurationPropertySources.attach(environment);
		return environment;
	}
	private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
		if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
			Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
			System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
		}
	}

7、创建 Banner 打印类

Banner printedBanner = printBanner(environment);
private Banner printBanner(ConfigurableEnvironment environment) {
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
				: new DefaultResourceLoader(getClassLoader());
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

8、创建应用上下文

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

9、准备异常报告器

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
		new Class[] { ConfigurableApplicationContext.class }, context);

10、准备应用上下文

prepareContext(context, environment, listeners, applicationArguments, printedBanner);
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	  //设置上下文环境
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		//拿到之前读取到所有ApplicationContextInitializer的组件,循环调用initialize方法
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		//设置是否允许bean的覆盖
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		//设置bean是否全局懒加载
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// 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);
	}

11、刷新应用上下文

refreshContext(context);
private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}

12、应用上下文刷新后置处理

afterRefresh(context, applicationArguments);
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	}

13、停止计时监控类

stopWatch.stop();
public void stop() throws IllegalStateException {
		if (this.currentTaskName == null) {
			throw new IllegalStateException("Can't stop StopWatch: it's not running");
		}
		long lastTime = System.nanoTime() - this.startTimeNanos;
		this.totalTimeNanos += lastTime;
		this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
		if (this.keepTaskList) {
			this.taskList.add(this.lastTaskInfo);
		}
		++this.taskCount;
		this.currentTaskName = null;
	}

14、输出日志记录执行主类名、时间信息

if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}

15、发布应用上下文启动完成事件

listeners.started(context);
void started(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.started(context);
		}
	}

16、执行所有 Runner 运行器

callRunners(context, applicationArguments);
private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		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);
			}
		}
	}

17、发布应用上下文就绪事件

listeners.running(context);
void running(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.running(context);
		}
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值