VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • SpringBoot启动流程

前言#

为什么要学习框架的启动流程?
因为这不仅是面试中常见的考点,而且掌握一个框架的启动流程,可以让你在运用它进行开发时游刃有余。甚至可以说,学习一个框架的起步,都是从学习框架的启动开始的。

下面会从源码角度对启动流程做一个剖析,建议读者可以跟着文章内容进行调试,那样可以理解的更透彻。

源码版本为 spring-boot-2.2.1.RELEASE.jar

启动流程#

初始化SpringApplication对象#

  • 获取所有的ApplicationContextInitializer接口的实现类
  • 获取所有的ApplicationListener接口的实现类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 获取所有的ApplicationContextInitializer接口的实现类
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // 获取所有的ApplicationListener接口的实现类
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

如何获取到实现类的呢?主要通过 getSpringFactoriesInstances 方法

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
        // 获取实现类的全限定类名,并去重
	// Use names and ensure unique to protect against duplicates
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 通过类名反射获取实现类实例
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        // Spring内置排序器对实例进行排序
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

那 SpringFactoriesLoader 的 loadFactoryNames 方法如何工作

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	String factoryTypeName = factoryType.getName();
        // 返回 factoryType 下的实现类名列表
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

// 获取类加载器下 META-INF/spring.factories 资源并解析
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	MultiValueMap<String, String> result = cache.get(classLoader);
        // 如果缓存中存在则直接返回
	if (result != null) {
		return result;
	}

        // FACTORIES_RESOURCE_LOCATION="META-INF/spring.factories"
        // 只要外部依赖中存在 spring.factories 文件配置,那么就会将文件绝对路径加载到 urls
	Enumeration<URL> urls = (classLoader != null ?
						classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
						ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
	result = new LinkedMultiValueMap<>();
        // 解析每个 spring.factories 文件
	while (urls.hasMoreElements()) {
		URL url = urls.nextElement();
		UrlResource resource = new UrlResource(url);
		Properties properties = PropertiesLoaderUtils.loadProperties(resource);
		for (Map.Entry<?, ?> entry : properties.entrySet()) {
			String factoryTypeName = ((String) entry.getKey()).trim();
			for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
				result.add(factoryTypeName, factoryImplementationName.trim());
			}
		}
		cache.put(classLoader, result);
		return result;
	}
}

spring.factories 内容示例:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

SpringApplication对象调用run方法#

(1)构造 SpringApplicationListeners,用来监听启动过程中的事件并回调。
SpringApplicationListeners 会存储 SpringApplicationListener 的实现类实例,并构成链表结构,默认只有一个 EventPublishRunListener,且优先级最高,位于链表首部。

获取所有 Listener 还是通过 getSpringFactoriesInstances 方法

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

SpringApplicationListeners 调用所有 EventPublishRunListener 的 starting 方法

class SpringApplicationRunListeners {
	private final List<SpringApplicationRunListener> listeners;

	void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}
}

SpringApplicationRunListener 回调匹配类型的 ApplicationListener 的 onApplicationEvent 方法

@Override
public void starting() {
        // 广播事件
	this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

@Override
public void multicastEvent(ApplicationEvent event) {
	multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	Executor executor = getTaskExecutor();
        // getApplicationListeners 获取匹配 type 类型的听众
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		} else {
			invokeListener(listener, event);
		}
	}
}

(2)封装命令行参数,创建 Environment,回调 environmentPrepared 事件,并打印横幅(banner)

// 封装参数到 ApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// listeners 回调 environmentPrepared 事件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 打印横幅
Banner printedBanner = printBanner(environment);

(3)加载上下文
实例化 ApplicationContext,需要判断创建 service web context, 还是新出现的 reactive web context, 或者默认的 context

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

预处理上下文

// 将环境变量写入上下文
context.setEnvironment(environment);
// 回调 ApplicationContextInitializer 的 initialize 方法
applyInitializers(context);
// 回调 Listener 的 contextPrepared 和 contextLoaded
listeners.contextPrepared(context);
listeners.contextLoaded(context);

刷新上下文

  • 完成 ioc 容器构建,如果是 web 应用会创建内嵌的 Tomcat
  • 扫描,加载外部组件自动配置信息(自动配置 @EnableAutoConfiguration)
  • 回调 Listener 的 started
  • 从ioc容器中获取所有的 ApplicationRunner 和 CommandLineRunner 进行回调。ApplicationRunner 先回调,CommandLineRunner 再回调

AutoConfigurationImportSelector#getAutoConfigurationEntry 加载自动配置信息

AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 过滤掉条件不满足的自动配置类(ConditionalOn)
configurations = filter(configurations, autoConfigurationMetadata);
 
出处:https://www.cnblogs.com/flowers-bloom/p/springboot-bootstrap.html


相关教程