SpringBoot应用启动流程源码解析
前言
Springboot应用在启动的时候分为两步:首先生成SpringApplication对象,运行SpringApplication的run方法,下面一一看一下每一步具体都干了什么
publicstaticConfigurableApplicationContextrun(Class>[]primarySources,String[]args){
returnnewSpringApplication(primarySources).run(args);
}
创建SpringApplication对象
publicSpringApplication(ResourceLoaderresourceLoader,Class>...primarySources){
this.resourceLoader=resourceLoader;
Assert.notNull(primarySources,"PrimarySourcesmustnotbenull");
//保存主配置类
this.primarySources=newLinkedHashSet<>(Arrays.asList(primarySources));
//判断当前是否一个web应用
this.webApplicationType=WebApplicationType.deduceFromClasspath();
//从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener
setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
//从多个配置类中找到有main方法的主配置类
this.mainApplicationClass=deduceMainApplicationClass();
}
其中从类路径下获取到META-INF/spring.factories配置的所有ApplicationContextInitializer和ApplicationListener的具体代码如下
publicfinalclassSpringFactoriesLoader{
/**spring.factories的位置*/
publicstaticfinalStringFACTORIES_RESOURCE_LOCATION="META-INF/spring.factories";
privatestaticfinalLoglogger=LogFactory.getLog(SpringFactoriesLoader.class);
/**
*缓存扫描后的结果,注意这个cache是static修饰的,说明是多个实例共享的
*其中MultiValueMap的key就是spring.factories中的key(比如org.springframework.boot.autoconfigure.EnableAutoConfiguration),
*其值就是key对应的value以逗号分隔后得到的List集合(这里用到了MultiValueMap,他是guava的一键多值map,类似Map>)
*/
privatestaticfinalMap>cache=newConcurrentReferenceHashMap<>();
privateSpringFactoriesLoader(){
}
/**
*AutoConfigurationImportSelector及应用的初始化器和监听器里最终调用的就是这个方法,
*这里的factoryType是EnableAutoConfiguration.class、ApplicationContextInitializer.class、或ApplicationListener.class
*classLoader是AutoConfigurationImportSelector、ApplicationContextInitializer、或ApplicationListener里的beanClassLoader
*/
publicstaticListloadFactoryNames(Class>factoryType,@NullableClassLoaderclassLoader){
StringfactoryTypeName=factoryType.getName();
returnloadSpringFactories(classLoader).getOrDefault(factoryTypeName,Collections.emptyList());
}
/**
*加载spring.factories文件的核心实现
*/
privatestaticMap>loadSpringFactories(@NullableClassLoaderclassLoader){
//先从缓存获取,如果获取到了说明之前已经被加载过
MultiValueMapresult=cache.get(classLoader);
if(result!=null){
returnresult;
}
try{
//找到所有jar中的spring.factories文件的地址
Enumerationurls=(classLoader!=null?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION):
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result=newLinkedMultiValueMap<>();
//循环处理每一个spring.factories文件
while(urls.hasMoreElements()){
URLurl=urls.nextElement();
UrlResourceresource=newUrlResource(url);
//加载spring.factories文件中的内容到Properties对象中
Propertiesproperties=PropertiesLoaderUtils.loadProperties(resource);
//遍历spring.factories内容中的所有的键值对
for(Map.Entry,?>entry:properties.entrySet()){
//获得spring.factories内容中的key(比如org.springframework.boot.autoconfigure.EnableAutoConfiguratio)
StringfactoryTypeName=((String)entry.getKey()).trim();
//获取value,然后按英文逗号(,)分割得到value数组并遍历
for(StringfactoryImplementationName:StringUtils.commaDelimitedListToStringArray((String)entry.getValue())){
//存储结果到上面的多值Map中(MultiValueMap)
result.add(factoryTypeName,factoryImplementationName.trim());
}
}
}
cache.put(classLoader,result);
returnresult;
}
catch(IOExceptionex){
thrownewIllegalArgumentException("Unabletoloadfactoriesfromlocation["+
FACTORIES_RESOURCE_LOCATION+"]",ex);
}
}
}
运行run方法
publicConfigurableApplicationContextrun(String...args){
//开始停止的监听
StopWatchstopWatch=newStopWatch();
stopWatch.start();
//声明一个可配置的ioc容器
ConfigurableApplicationContextcontext=null;
FailureAnalyzersanalyzers=null;
//配置awt相关的东西
configureHeadlessProperty();
//获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
SpringApplicationRunListenerslisteners=getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
listeners.starting();
try{
//封装命令行参数
ApplicationArgumentsapplicationArguments=newDefaultApplicationArguments(
args);
//准备环境
ConfigurableEnvironmentenvironment=prepareEnvironment(listeners,
applicationArguments);
//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
BannerprintedBanner=printBanner(environment);
//创建ApplicationContext;决定创建web的ioc还是普通的ioc,
//通过反射创建ioc容器((ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);)
context=createApplicationContext();
//出现异常之后做异常分析报告
analyzers=newFailureAnalyzers(context);
//准备上下文环境;将environment保存到ioc中;而且applyInitializers();
//applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
//回调所有的SpringApplicationRunListener的contextPrepared();
//
prepareContext(context,environment,listeners,applicationArguments,
printedBanner);
//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
//刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
refreshContext(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
//ApplicationRunner先回调,CommandLineRunner再回调
afterRefresh(context,applicationArguments);
//所有的SpringApplicationRunListener回调finished方法
listeners.finished(context,null);
stopWatch.stop();
if(this.logStartupInfo){
newStartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(),stopWatch);
}
//整个SpringBoot应用启动完成以后返回启动的ioc容器;
returncontext;
}
catch(Throwableex){
handleRunFailure(context,listeners,analyzers,ex);
thrownewIllegalStateException(ex);
}
}
几个重要的事件回调机制
配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
只需要放在ioc容器中
ApplicationRunner
CommandLineRunner
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。