SpringBoot源码解读三【启动过程】

  前文我们分别谈了框架引用、认识框架。现在就正式通过启动过程代码跟踪,分析内部的实现逻辑


研究源码的方法

  1. 不要死扣细节,容易蒙(!!!)
  2. 关注方法上的注释
  3. 优秀的代码,在命名上很有讲究,见名知意

源码

启动类

package com.walker.springboot.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootStudyApplication {

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

}

SpringApplication类调用静态的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);
	}

生成SpringApplication对象并调用对象run方法

public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}

	/**
	 * Create a new {@link SpringApplication} instance. The application context will load
	 * beans from the specified primary sources (see {@link SpringApplication class-level}
	 * documentation for details). The instance can be customized before calling
	 * {@link #run(String...)}.
	 * @param resourceLoader the resource loader to use
	 * @param primarySources the primary bean sources
	 * @see #run(Class, String[])
	 * @see #setSources(Set)
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	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应用的类型,初始化ApplicationListener的webApplicationType 属性
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// 引导注册初始化器
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		// 从spring.factories文件中获取应用上线文初始化器(bean工厂),初始化ApplicationListener的initializers属性
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		// 从spring.factories文件中获取应用监听器,初始化ApplicationListener的listeners属性
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 获取主函数的类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

	/**
	 * 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) {
		// 虚拟机时间源的时间 单位:纳秒 
		long startTime = System.nanoTime();
		// 创建引导上下文
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		// 获取SpringApplicationRunListener 应用运行监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 调用SpringApplicationRunListeners的starting方法。会有对应的监听器进行业务逻辑
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			// 命令行参数进行封装
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 环境准备
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			// 配置忽略的bean信息 不做实例化
			configureIgnoreBeanInfo(environment);
			// 打印banner
			Banner printedBanner = printBanner(environment);
			// 创建应用上下文 beanFactory
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			// 准备上下文
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			// 刷新上下文
			refreshContext(context);
			// 刷新结束
			afterRefresh(context, applicationArguments);
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			// 
			listeners.started(context, timeTakenToStartup);
			// 启动后,
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
			listeners.ready(context, timeTakenToReady);
		}
		catch (Throwable ex) {
			// 处理运行时异常
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

阶段分析

准备环境


private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	// 为应用环境添加属性资源 把命令行资源添加到应用环境中
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach(environment);
	// 通过监听器添加了多个属性资源
	listeners.environmentPrepared(bootstrapContext, environment);
	// 把应用环境中的默认的属性资源挪到最后
	DefaultPropertiesPropertySource.moveToEnd(environment);
	Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
			"Environment prefix cannot be set via properties.");
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = convertEnvironment(environment);
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

// 根据不同的应用类型,创建不同的环境对象
private ConfigurableEnvironment getOrCreateEnvironment() {
	if (this.environment != null) {
		return this.environment;
	}
	switch (this.webApplicationType) {
	case SERVLET:
		return new ApplicationServletEnvironment();
	case REACTIVE:
		return new ApplicationReactiveWebEnvironment();
	default:
		return new ApplicationEnvironment();
	}
}

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		// 如果已存在默认的属性资源,进行属性合并
		if (!CollectionUtils.isEmpty(this.defaultProperties)) {
			DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
		}
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(
						new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

这一阶段主要是识别对应的属性资源并添加到环境中,主要包括如下内容:

  • defaultProperties
  • springApplicationCommandLineArgs
  • random(随机变量random.value等)
  • spring.application.json
  • systemEnvironment
  • systemProperties

注:罗列的内容没有先后顺序

使用了线程安全的CopyOnWriteArrayList集合,

提供的取值方法,先后顺序决定了属性资源的优先级。

protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
		if (this.propertySources != null) {
			for (PropertySource<?> propertySource : this.propertySources) {
				if (logger.isTraceEnabled()) {
					logger.trace("Searching for key '" + key + "' in PropertySource '" +
							propertySource.getName() + "'");
				}
				Object value = propertySource.getProperty(key);
				if (value != null) {
					if (resolveNestedPlaceholders && value instanceof String) {
						value = resolveNestedPlaceholders((String) value);
					}
					logKeyFound(key, propertySource, value);
					return convertValueIfNecessary(value, targetValueType);
				}
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("Could not find key '" + key + "' in any property source");
		}
		return null;
	}

创建应用上下文

// 创建应用上下文
protected ConfigurableApplicationContext createApplicationContext() {
	return this.applicationContextFactory.create(this.webApplicationType);
}

// 查看应用上下文工厂初始化时的值
private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;


// ApplicationContextFactory 
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
	try {
		// 从spring.factories中获取应用上下文工厂 并遍历
		for (ApplicationContextFactory candidate : SpringFactoriesLoader
				.loadFactories(ApplicationContextFactory.class, ApplicationContextFactory.class.getClassLoader())) {
				// 根据应用类型创建应用上下文
			ConfigurableApplicationContext context = candidate.create(webApplicationType);
			if (context != null) {
				return context;
			}
		}
		// 默认注解配置的应用上下文
		return new AnnotationConfigApplicationContext();
	}
	catch (Exception ex) {
		throw new IllegalStateException("Unable create a default ApplicationContext instance, "
				+ "you may need a custom ApplicationContextFactory", ex);
	}
};


# Application Context Factories
org.springframework.boot.ApplicationContextFactory=\
org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext.Factory,\
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext.Factory

最终创建了:AnnotationConfigServletWebServerApplicationContext

public AnnotationConfigServletWebServerApplicationContext() {
	// 解读器
	this.reader = new AnnotatedBeanDefinitionReader(this);
	// 扫码器
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

类图
这图关系还是很复杂,从图可以看出AnnotationConfigServletWebServerApplicationContext 属于BeanFactory

准备应用上下文

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		// 添加环境对象
		context.setEnvironment(environment);
		
		postProcessApplicationContext(context);
		//添加初始化器
		applyInitializers(context);
		listeners.contextPrepared(context);
		bootstrapContext.close(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);
		}
		if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
			((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
			if (beanFactory instanceof DefaultListableBeanFactory) {
				((DefaultListableBeanFactory) beanFactory)
						.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
			}
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// 扫描、读取  转换为BeanDefinition 
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}

这个阶段:通过包扫描识别到需要实例化的类,并生成BeanDefinition对象,为下一阶段生成bean做准备

刷新应用上下文

private void refreshContext(ConfigurableApplicationContext context) {
	if (this.registerShutdownHook) {
		shutdownHook.registerApplicationContext(context);
	}
	refresh(context);
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
	applicationContext.refresh();
}

AbstractApplicationContext.refresh

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);
			beanPostProcess.end();

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
			contextRefresh.end();
		}
	}
}

刷新后

调用了一个空方法,什么也没有做

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

调用Runners

private void callRunners(ApplicationContext context, ApplicationArguments args) {
	List<Object> runners = new ArrayList<>();
	//Bean工厂中获取ApplicationRunner的实例集合
	runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
	//Bean工厂中获取CommandLineRunner的实例集合
	runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
	//Runner排序基于order注解排序(值越小优先级越高)
	AnnotationAwareOrderComparator.sort(runners);
	//遍历 调用runner
	for (Object runner : new LinkedHashSet<>(runners)) {
		if (runner instanceof ApplicationRunner) {
			callRunner((ApplicationRunner) runner, args);
		}
		if (runner instanceof CommandLineRunner) {
			callRunner((CommandLineRunner) runner, args);
		}
	}
}

通过实现ApplicationRunner、CommandLineRunner,可以在应用启动后,执行一些业务逻辑(缓存的操作,系统初始化操作),两个接口无本质差别,不过更推荐用ApplicationRunner,ApplicationArguments参数,对以"–"开头的参数(spring格式)进行的解析,可以通过getOptionValues获取到对应的值。

总结

本文根据启动过程的阶段进行分析,没有进行深入介绍。我的计划先了解整个脉络,稍后对每个脉络做深入分析。不仅仅要知道框架是如何做?还要了解为什么这样做?这样我们才能在学习中收获更多。


版权声明:本文为leilecoffee原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。