title: SpringBoot启动流程—-SpringApplication类
author: thetianxia
readmore: true
categories: [Java,框架]
tags: [Java,面试,SpringBoot]
SpringBoot启动类 2.4.5
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
启动类的代码非常简单,我们只需要在SpringBoot项目启动类加上注解@SpringBootApplication,即可标注该类是启动类。在该类的main方法中调用了
SpringApplication.run(Application.class),所以启动流程就在run中。通过debug,我们看一下源码。
//1、main方法进来之后,调用了这个run方法,然后这个run又封装了一下参数,调用另一个重载方法run
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
//2、该run方法,首先新创建一个SpringApplication,该类构造器接受一个启动类参数对象,在构造器中,SpringBoot进行了一系列参数初始化。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
SpringApplication构造器,初始化
//3、run方法创建新的SpringApplication对象,调用该构造器,该构造器又调用另一个构造器
public SpringApplication(Class<?>... primarySources) {
//默认资源加载器ResourceLoader为null
this((ResourceLoader)null, primarySources);
}
//4、初始化
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet(); //配置sources
this.bannerMode = Mode.CONSOLE; //配置横幅,默认打印到控制台。Mode枚举 OFF关闭,CONSOLE控制台打印,LOG日志打印;
this.logStartupInfo = true; //配置是否开启日志,默认开启
this.addCommandLineProperties = true; //配置是否添加命令行属性,默认开启
this.addConversionService = true; //是否添加转换服务,默认开启
this.headless = true; //headless模式
this.registerShutdownHook = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT; //DefaultApplicationStartup
this.resourceLoader = resourceLoader; //null
Assert.notNull(primarySources, "PrimarySources must not be null"); //如果没有启动类,启动失败。primarySources一般只有一个启动类,或者null
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); //保存主配置类
this.webApplicationType = WebApplicationType.deduceFromClasspath(); //判断web类型,SERVLET
this.bootstrapRegistryInitializers = this.getBootstrapRegistryInitializersFromSpringFactories(); //获取所有的BootstrapRegistryInitializer实现类保存在List<BootstrapRegistryInitializer> bootstrapRegistryInitializers,锚点1
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //从资源文件配置ApplicationContextInitializer实例并存在List<ApplicationContextInitializer<?>> initializers;锚点2
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //从资源文件创建应用监听器,保存在List<ApplicationListener<?>> listeners
this.mainApplicationClass = this.deduceMainApplicationClass(); //配置应用的主方法所在类
}
锚点1
SpringBoot启动时初始化上下文时,最终会调用该方法。再改方法中获取classLoader,因为构造器中resourceLoader是null,所以得到的是默认构造器
然后执行该方法SpringFactoriesLoader.loadFactoryNames(type, classLoader),锚点1之后的流程如下。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
//最终会调用该方法。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader(); //return this.resourceLoader != null ? this.resourceLoader.getClassLoader() : ClassUtils.getDefaultClassLoader();返回系统默认类加载器
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
然后进入SpringFactoriesLoader.loadFactoryNames(type, classLoader)。
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader; //默认加载器
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName(); //锚点1处是BootstrapRegistryInitializer.class类的全类名
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
获得全类名之后,进入loadSpringFactories(classLoaderToUse)方法,并得到一个Map类。该方法会从”META-INF/spring.factories”下的文件中读取配置。SpringBoot中只有如图三个路径下存在”META-INF/spring.factories”。我们以锚点1的BootstrapRegistryInitializer为例。
urls中存在3个地址,分别在spring-boot,spring-boot-autoconfigure,spring-beans中。循环将对应地址的文件读入为properties,内容如下图。
如果缓存没有,则读取配置文件,获得Enumeration类型的urls,Enumeration的key是HashTable并且对应的值也存于HashTable中。因此该类将配置文件中的内容做映射。之后通过迭代,获得每一个key和对应的values。
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
//先从缓存获取,如果有就直接返回
Map<String, List<String>> result = (Map)cache.get(classLoader);
if (result != null) {
return result;
} else {
HashMap result = new HashMap();
try {
//没有则从"META-INF/spring.factories"文件中读取,获取"META-INF/spring.factories"的url
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
//遍历url
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource); //从url中读入数据
Iterator var6 = properties.entrySet().iterator(); //获得迭代器
//迭代
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next(); //String,String
String factoryTypeName = ((String)entry.getKey()).trim(); //去掉key字符串开头和结尾的空白
//value转为数组
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); //将value字符转为数组
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> { //第一次会返回空数组,并将第一个元素去掉开头和结尾的空白并添加到数组,之后都获取该数组并向其中添加元素。
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
//最后将map中所有key对应的value去重后更新
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
cache.put(classLoader, result); //放入缓存
return result; //返回map
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
返回之后,会通过getOrDefault方法返回BootstrapRegistryInitializer.class对应的配置集合。然后执行List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
该方法通过反射,用names中的全部类的全类名创建实例对象集合,然后排序之后返回。
返回之后,保存到SpringApplication对象的属性中。
锚点2
初始化BootstrapRegistryInitializer.class之后,会初始化ApplicationContextInitializer和ApplicationListener监听器相关的类。过程同锚点1一样。只不过在loadSpringFactories方法中,会直接返回缓存中的map并返回对应的list。
Run具体启动
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch(); //计时
stopWatch.start();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
//创建并启动监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args); //锚点3,获取监听器
listeners.starting(bootstrapContext, this.mainApplicationClass); //锚点4,启动监听器
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); //锚点7,准备环境
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment); //根据配置打印banner
//创建ioc
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
锚点3
SpringApplicationRunListeners listeners = this.getRunListeners(args);这个方法比较重要,目的是获取一个封装的SpringApplicationRunListeners对象。该类中一个属性List listeners中最后会有一个元素EventPublishingRunListener。
下面,通过断点,我们看一下封装过程。
可以看到getRunListeners直接new了一个SpringApplicationRunListeners。之后我们看该构造函数,现在我们先看参数this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)最后会是什么。
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}
这个方法,我们在之前SpringApplication构造其中,就见过多次。它从一个map中获取对应的List集合。我们进去看一下,果然,一样的配方。最后names只有一个元素,就是EventPublishingRunListener类的全限定类名。之后又调用了List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);这行代码进行反射获取实例。最后代码会运行到EventPublishingRunListener的构造器处。我们往下看。
标注的这一行,将过去的构造函数和参数传入,反射创建对象。
ctor就是上一步的传入的构造函数,这里直接传入参数开始构建。参数中包含的就是之前new的并且初始化的SpringApplication对象。
调用EventPublishingRunListener构造器创建对象。该类有三个参数,application是通过参数传递的,用来获取初始化时创建的监听器对象集合,并获取迭代器var3。然后将监听器封装到initialMulticaster属性中。initialMulticaster的类型是 public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster,它的父类中,有一个内部类,该内部类中有一个集合,最终这些listener会存到该集合中。
内部类部分代码
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized(this.defaultRetriever) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
//内部类
private class DefaultListenerRetriever {
public final Set<ApplicationListener<?>> applicationListeners; //最终存放监听器处
public final Set<String> applicationListenerBeans;
private DefaultListenerRetriever() {
this.applicationListeners = new LinkedHashSet();
this.applicationListenerBeans = new LinkedHashSet();
}
}
因为初始化一共有9个监听器,所以最终这个集合里面会添加9个监听器。如下图,返回的参数就是instances,里面封装了一个EventPublishingRunListener,EventPublishingRunListener里面有个属性initialMulticaster,里面又封装了一个包含9个监听器的集合。封装套娃。。。。最后通过SpringApplicationRunListeners构造函数,赋值给listeners。最后返回生成的SpringApplicationRunListeners对象。
到此为止,锚点3结束。如果套的头晕,建议多看几遍就好了。
锚点4
获得监听器之后,启动监听器。这个方法最后调用了doWithListeners方法。我们可以看到里面将linsteners中的监听器(其实就是EventPublishingRunListener)分别执行lambda中listener.starting(bootstrapContext),所以我们去EventPublishingRunListener中找对应的方法。
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
this.doWithListeners("spring.boot.application.starting", (listener) -> {
listener.starting(bootstrapContext);
}, (step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction, Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
调用该方法
然后来到SimpleApplicationEventMulticaster,最终调用的是下面这个方法。该方法中,重要的是Iterator var5 = this.getApplicationListeners(event, type).iterator();获取符合eventType的监听器的迭代器。我们进入看下。
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Executor executor = this.getTaskExecutor(); //null
Iterator var5 = this.getApplicationListeners(event, type).iterator(); //锚点5
//从锚点6回来,遍历符合条件的监听器,并执行
while(var5.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
//执行
this.invokeListener(listener, event);
}
}
}
this.invokeListener(listener, event)最后会执行到这里,根据监听器执行不同的逻辑。
锚点5
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource(); //初始化创建的SpringApplication对象
Class<?> sourceType = source != null ? source.getClass() : null; //SpringApplication的全限定类名
AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType); //将eventType和sourceType封装一个key,后面获取 existingRetriever
AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;
AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey); //因为开始缓存没有,所以是null,所以进入下边的if
if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
//因为第一次retrieverCache缓存没有,所以new了一个newRetriever,然后放入缓存,cacheKey作为key,newRetriever作为值
newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();
//因为不存在,所以newRetriever被放入,返回null,所以existingRetriever是null
existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
if (existingRetriever != null) {
newRetriever = null;
}
}
//existingRetriever==null,不会执行
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners(); //符合条件的监听器集合,分析见锚点6
if (result != null) {
return result;
}
}
//这一步筛选符合条件的监听器并返回。锚点6
return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
锚点6
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList();
Set<ApplicationListener<?>> filteredListeners = retriever != null ? new LinkedHashSet() : null;
Set<String> filteredListenerBeans = retriever != null ? new LinkedHashSet() : null;
LinkedHashSet listeners;
LinkedHashSet listenerBeans;
synchronized(this.defaultRetriever) {
//我们 锚点3分析过,this.defaultRetriever.applicationListeners存放的是加载classpath路径下的9个监听器
//这里加锁,为了防止在执行这一步的同时值被其他线程修改
listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
}
Iterator var9 = listeners.iterator();
while(var9.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var9.next();
//通过方法名字,我们可以推测,如果listener符合eventType和sourceType,那么返回true,最终有4个监听器满足
if (this.supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
//第一次加入filteredListeners
filteredListeners.add(listener);
}
//符合条件加入filteredListeners
allListeners.add(listener);
}
}
//listenerBeans大小为0,不会执行
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = this.getBeanFactory();
Iterator var16 = listenerBeans.iterator();
while(var16.hasNext()) {
String listenerBeanName = (String)var16.next();
try {
if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
filteredListeners.add(listener);
} else {
filteredListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
} else {
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
filteredListeners.remove(listener);
}
allListeners.remove(listener);
}
} catch (NoSuchBeanDefinitionException var13) {
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
//将过滤的结果存入缓存,下次通过cacheKey直接获取
if (retriever != null) {
if (filteredListenerBeans.isEmpty()) {
retriever.applicationListeners = new LinkedHashSet(allListeners);
retriever.applicationListenerBeans = filteredListenerBeans;
} else {
retriever.applicationListeners = filteredListeners;
retriever.applicationListenerBeans = filteredListenerBeans;
}
}
return allListeners; //锚点6结束,回到锚点4
}
锚点7
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment(); //获取系统配置信息,以及控制台配置
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment); //处理环境准备完成相关的监听器,过程参考锚点3到锚点6,不同的是type,因此广播的监听器不同。
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
我们进入getOrCreateEnvironment方法,因为开始的时候环境是空,所以这里会创建StandardServletEnvironment(),里面进去这里会先调用父类的构造器,StandardEnvironment,AbstractEnvironment。
所以最终调用的是AbstractEnvironment的构造器,具体逻辑也是在这里执行的。
这段逻辑里面,进行了一些初始值的设置,然后再最后一行代码进行了重要的操作。最后一行代码执行的不是该类的方法,而是StandardServletEnvironment类的重写方法。
StandardServletEnvironment执行该方法后,又调用父类StandardEnvironment的重写方法。
这里进行了一些初值的设置。
重点在父类中。getSystemProperties方法中,会调用System.getProperties(),从这个方法里面就可以获取计算机系统的属性。
接下来会执行这一句。具体作用就如同注释一样。因为到这里环境准备的差不多了,所以就要处理环境准备之后的一些监听器。因此eventType类型是ApplicationEnvironmentPreparedEvent,找到之后进行广播。
锚点8
web项目,会创建一个AnnotationConfigServletWebServerApplicationContext()类。
之后创建启动器,在准备需要创建的beans。
prepareContext中会调用下面这个方法。可以看到,这里将this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class))这个地方从配置中读到的初始化相关类进行遍历,并且初始化。初始化前会进行断言,如果不能初始化则抛出异常。
之后会执行相应的监听器。并且会注册单例对象的类名。
prepareContext执行完毕之后,会调用refreshContext方法,该方法会将容器的对象刷新激活,之后处理刷新之后的操作。
在激活对象的时候,我们深入会发现,在refresh方法中,会调用onRefresh方法。在这个地方会启动tomcat。启动tomcat之后还会加载一些其他bean。
到此,springboot启动完毕。