# SpringBoot启动原理 #
1.创建SpringBoot时默认生成一个启动类
@SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
2.启动时调用SpringApplication的run方法
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
//调用SpringApplication类中的重载run方法
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
3.此时调用两个方法:先创建一个SpringApplication对象,运行run方法
//创建SpringApplication对象,参数为Class<?>[SpringBootWebApplication.class]
new SpringApplication(primarySources);
//运行run方法
run(args);
4.创建SpringApplication对象时执行下面代码
public SpringApplication(Class<?>... primarySources) {
//调用重载构造方法
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//resourceLoader为null
this.resourceLoader = resourceLoader;
//primarySources为Class<?>[SpringBootWebApplication.class]
Assert.notNull(primarySources, "PrimarySources must not be null");
//此时primarySources由数组变为LinkedHashSet集合
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//4.1判断应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//4.2从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//4.3从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//4.4从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
4.1.调用WebApplicationType.deduceFromClasspath()方法判断应用类型
//判断当前应用是普通web应用、响应式web应用还是非web应用
static WebApplicationType deduceFromClasspath() {
//isPresent方法判断所提供的类名的类是否存在,且可以被加载
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
//应用是响应式web应用
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
//非web应用
return WebApplicationType.NONE;
}
}
//普通web应用
return WebApplicationType.SERVLET;
}
4.2.从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
setInitializers(
//4.2.1获取Spring工厂实例
(Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
4.2.1.获取Spring工厂实例
getSpringFactoriesInstances(
ApplicationContextInitializer.class)
//此处type参数为ApplicationContextInitializer.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
//调用重载方法
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
//获取类加载器
ClassLoader classLoader = getClassLoader();
//4.2.1.1使用LinkedHashSet存放加载的工厂名称防止重复
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//4.2.1.2创建Spring工厂实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
//对实例进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
4.2.1.1使用LinkedHashSet存放加载的工厂名称防止重复
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//加载工厂名称,此处factoryClass参数为ApplicationContextInitializer.class
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
//此时factoryClassName为org.springframework.context.ApplicationContextInitializer
String factoryClassName = factoryClass.getName();
//加载Spring工厂,并从中获取key为org.springframework.context.ApplicationContextInitializer的value.此时值为:
//org.springframework.context.ApplicationContextInitializer=\
//org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
//org.springframework.boot.context.ContextIdApplicationContextInitializer,\
//org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
//org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
//加载Spring工厂
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//第一次调用该方法,此时cache只是一个空集合
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//加载所有的/META-INF/spring.factories文件
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
//将spring.factories文件转为properties文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
//将所有的spring.factories文件中的数据存入cache中
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
4.2.1.2创建Spring工厂实例
//创建Spring工厂实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
//遍历传入的names,对其进行实例化,放入instances中返回
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
//根据name和classLoader获取Class对象
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
//获取指定参数类型的所有构造器,包括public的和非public的
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
//创建实例化对象
T instance = (T) BeanUtils.instantiateClass(constructor, args);
//加如instances中
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
4.3从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListener和4.2流程类似
5.运行run方法
/**
* 运行spring应用,创建并刷新新的spring容器
*/
public ConfigurableApplicationContext run(String... args) {
//首先创建开始停止的监听
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//与awt应用有关的配置
configureHeadlessProperty();
//5.1从类路径下找到META‐INF/spring.factories获取SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的SpringApplicationRunListeners的starting方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//5.2准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//打印banner图标
Banner printedBanner = printBanner(environment);
//创建ioc容器,根据环境不同创建不同的ioc容器
context = createApplicationContext();
//出现异常用来查看异常报告
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//5.3准备上下文环境
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//5.4刷新容器,ioc容器初始化流程
refreshContext(context);
//5.5从ioc容器中获取ApplicationRunner和CommandLineRunner并进行回调
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
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);
}
//springboot启动完成返回ioic容器
return context;
}
5.2准备环境
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 获取或创建环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境
configureEnvironment(environment, applicationArguments.getSourceArgs());
//回调所有的SpringApplicationRunListeners的environmentPrepared方法,表示环境准备完成
listeners.environmentPrepared(environment);
//将环境绑定到spring应用中
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
5.3准备上下文环境
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置环境到ioc容器中
context.setEnvironment(environment);
//使用后置处理器给ioc容器注册bean
postProcessApplicationContext(context);
//回调4.2步骤中获取的所有ApplicationContextInitializer的initialize方法
applyInitializers(context);
//回调5.1步骤中获取的所有SpringApplicationRunListener的contextPrepared方法
listeners.contextPrepared(context);
//记录日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 注册命令行参数
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
//将banner注册进来
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 获取主类
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
//回调5.1步骤中获取的所有SpringApplicationRunListener的contextLoaded方法
listeners.contextLoaded(context);
}
5.5从ioc容器中获取ApplicationRunner和CommandLineRunner并进行回调,其中ApplicationRunner优先级高于CommandLineRunner
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
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);
}
}
}
SpringBoot启动原理
最新推荐文章于 2021-03-30 14:42:05 发布