Spring Boot启动原理

原文地址:https://maiyikai.github.io/2019/03/22/1553480412

如何启动一个SpringBoot应用?
	public class Test{
		public static void main(String[] args){
			SpringApplication springApplication = new SpringApplication(Test.class);
			springApplication.run(args);	
		}
	}
解析创建SpringApplication对象
源码1

SpringApplication构造方法:

	public SpringApplication(Object... sources) {
		initialize(sources);
	}
源码2(initialize(…))

初始化SpringAppcation

	private void initialize(Object[] sources) {
		//保存主配置类
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
		//判断当前应用是否为WEB应用
		this.webEnvironment = deduceWebEnvironment();
		//通过类路径META-INF/spring.factories文件获取ApplicationContextInitializer类型的实例,并保存
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		//通过类路径META-INF/spring.factories文件获取ApplicationListener类型的实例,并保存
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		//从多个配置类中找到有main方法的主配置类
		this.mainApplicationClass = deduceMainApplicationClass();
	}
源码3 getSpringFactoriesInstances(…)

获取通过META-INF/spring.factories文件获取到的对应的类路径下的实例

	//通过类路径META-INF/spring.factories文件获取ApplicationContextInitializer类型的实例
	private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		//通过类路径META-INF/spring.factories文件获取ApplicationContextInitializer.class类型的类名
		Set<String> names = new LinkedHashSet<String>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		//获取实例
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
源码4(deduceMainApplicationClass())

从运行类的堆栈中获取含有main方法的类

	//从运行类的堆栈中获取含有main方法的类
	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}
解析springApplication.run(args)
源码1(run(…))

run方法

	public ConfigurableApplicationContext run(String... args) {
		//跑马灯对象--用于记录运行时间
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
		configureHeadlessProperty();
		//通过META-INF/spring.factories获取SpringApplicationRunListener类型的实例
		SpringApplicationRunListeners listeners = getRunListeners(args);
		//遍历回调SpringApplicationRunListener的starting方法--既启动监听器
		listeners.starting();
		try {
			//封装命令行参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			//环境准备,完成后遍历回调SpringApplicationRunListener的environmentPrepared方法对监听器配置环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			//打印Banner-既控制台显示的Spring....
			Banner printedBanner = printBanner(environment);
			//根据创建的环境判断,是创建web容器,还是普通的IOC容器
			context = createApplicationContext();
			//注册异常分析器
			analyzers = new FailureAnalyzers(context);
			//准备上下文
			//遍历回调ApplicationContextInitializer的initialize事件
			//遍历回调SpringApplicationRunListeners中的contextPrepared事件
			//环境准备完成之后,遍历回调SpringApplicationRunListeners中的contextLoaded事件
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			//刷新上下文,初始化所有自动配置类
			refreshContext(context);
			//遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法
			afterRefresh(context, applicationArguments);
			//调用所有的SpringApplicationRunListener的finished()方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程
			listeners.finished(context, null);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}
源码2(getRunListeners(…))

通过类路径META-INF/spring.factories文件获取ApplicationContextInitializer类型的实例,并将其封装到SpringApplicationRunListeners实例

	//创建实例 SpringApplicationRunListeners
	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		//通过META-INF/spring.factories获取SpringApplicationRunListener类型的实例
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}
源码3(prepareEnvironment(…))

准备环境

	//准备环境
	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		//创建环境
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		//配置环境
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		//遍历回调SpringApplicationRunListener的environmentPrepared方法
		listeners.environmentPrepared(environment);
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}
源码4(createApplicationContext())

根据创建的环境判断,是创建web容器,还是普通的IOC容器

	//根据创建的环境判断,是创建web容器,还是普通的IOC容器
	protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				contextClass = Class.forName(this.webEnvironment
						? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
	}
源码5(prepareContext(…))

准备上下文

	//准备上下文
	private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		//设置环境
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		//遍历回调ApplicationContextInitializer的initialize事件--即上下文注入并初始化
		applyInitializers(context);
		//遍历回调SpringApplicationRunListeners中的contextPrepared事件--即上下注入
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// Add boot specific singleton beans
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
		Set<Object> sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));
		//遍历回调SpringApplicationRunListeners中的contextLoaded事件--即加载上下文
		listeners.contextLoaded(context);
	}

综上,SpringApplication.run()总共做了两件是:

  1. 创建了SpringApplication对象,初始化的时候,判断是否为WEB应用,并将通过配置文件META-INF/spring.factories找到对应的上下文类路径和监听器路径,将其实例化并且保存起来。
  2. 运行run方法,通过配置文件META-INF/spring.factories找到对应的监听器路径,将其实例化并启动。创建环境和创建上下文,并为监听器配置。刷新上下文,然后调用所有的监听器的finished()方法,广播SpringBoot已经完成了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值