springboot启动过程一.docx
《springboot启动过程一.docx》由会员分享,可在线阅读,更多相关《springboot启动过程一.docx(11页珍藏版)》请在冰豆网上搜索。
springboot启动过程一
SpringBoot启动过程
(一)
之前在排查一个线上问题时,不得不仔细跑了很多遍SpringBoot的代码,于是整理一下,我用的是1.4.3.RELEASE。
首先,普通的入口,这没什么好说的,我就随便贴贴代码了:
SpringApplication.run(Application.class,args);
-->
publicstaticConfigurableApplicationContextrun(Objectsource,String...args){
returnrun(newObject[]{source},args);
}
publicstaticConfigurableApplicationContextrun(Object[]sources,String[]args){
returnnewSpringApplication(sources).run(args);
}
也就是一个静态方法,调用了构造函数创建实例,构造的参数是Object数组,这里new这个数组的时候传入了一个元素就是启动类的类对象实例(一般就是“newObject[]{Application.class”}),构造函数里调用了一个initialize方法。
SpringApplication的initialize方法,首先在Object数组有值的情况下将数组放入一个final的类实例私有Object的Set集合中;然后用deduceWebEnvironment方法判断当前应用环境是否是web环境,判断逻辑是看Classpath是否同时存在javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext,缺一就认为不是。
然后,调用setInitializers方法,设置类实例的私有List<ApplicationContextInitializer<?
>>类型变量initializers:
publicvoidsetInitializers(
Collection<?
extendsApplicationContextInitializer<?
>>initializers){
this.initializers=newArrayList<ApplicationContextInitializer<?
>>();
this.initializers.addAll(initializers);
}
设置的时候会先new,也就是说这方法每次都是整体更换,不会追加。
这个方法的参数都是各个模块中配置在META-INF/spring.factories中的key为org.springframework.context.ApplicationContextInitializer的值,这些类都是接口ApplicationContextInitializer<CextendsConfigurableApplicationContext>的泛型实现。
private<T>Collection<?
extendsT>getSpringFactoriesInstances(Class<T>type,
Class<?
>[]parameterTypes,Object...args){
ClassLoaderclassLoader=Thread.currentThread().getContextClassLoader();
//Usenamesandensureuniquetoprotectagainstduplicates
Set<String>names=newLinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type,classLoader));
List<T>instances=createSpringFactoriesInstances(type,parameterTypes,
classLoader,args,names);
AnnotationAwareOrderComparator.sort(instances);
returninstances;
}
使用SpringFactoriesLoader.loadFactoryNames方法去取上面说的被配置的ApplicationContextInitializer的名字放进Set<String>中,并用反射创建这些名字的实例。
setInitializers方法之后又是setInitializers,参数同上都是getSpringFactoriesInstances方法获取,只不过这次参数Class<T>type泛型类型是org.springframework.context.ApplicationListener。
initialize方法的最后一个步是设置实例的Class<?
>类型私有属性mainApplicationClass,获取设置值的方法deduceMainApplicationClass:
privateClass<?
>deduceMainApplicationClass(){
try{
StackTraceElement[]stackTrace=newRuntimeException().getStackTrace();
for(StackTraceElementstackTraceElement:
stackTrace){
if("main".equals(stackTraceElement.getMethodName())){
returnClass.forName(stackTraceElement.getClassName());
}
}
}
catch(ClassNotFoundExceptionex){
//Swallowandcontinue
}
returnnull;
}
实例化SpringApplication后调用了它的run实例方法(注意不是上面的静态方法)。
一进run方法首先启动了StopWatch,这个StopWatch的功能在类的注释写可,大概意思是这是个简单的秒表,用于在开发过程中方便程序员调试性能等,非线程安全,不建议用于生产。
configureHeadlessProperty设置使用Headless,对于只有远程登录使用的服务器来说这样性能要好一些。
接着是加载用于这个run方法启动过程的监听器,依然是getSpringFactoriesInstances方法,这次的类型是org.springframework.boot.SpringApplicationRunListener:
#RunListeners
org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener
SpringApplicationRunListeners(Loglog,
Collection<?
extendsSpringApplicationRunListener>listeners){
this.log=log;
this.listeners=newArrayList<SpringApplicationRunListener>(listeners);
}
先是加载所有可用监听,然后初始化SpringApplicationRunListeners对象,最后循环启动所有SpringApplicationRunListener监听。
启动监听的方法:
@Override
publicvoidstarted(){
this.initialMulticaster
.multicastEvent(newApplicationStartedEvent(this.application,this.args));
}
ApplicationStartedEvent实例化传了两个参数,先看第一个参数this.application是怎么来的,实例的SpringApplication的run方法中,用于获取SpringApplicationRunListener,也就是前面说的getSpringFactoriesInstances被调用时:
privateSpringApplicationRunListenersgetRunListeners(String[]args){
Class<?
>[]types=newClass<?
>[]{SpringApplication.class,String[].class};
returnnewSpringApplicationRunListeners(logger,getSpringFactoriesInstances(
SpringApplicationRunListener.class,types,this,args));
}
getSpringFactoriesInstances方法的参数包含SpringApplication.class和this,这两个参数被传入createSpringFactoriesInstances方法:
可以看到,是通过反射创建实例的时候,将SpringApplication中的this传进来EventPublishingRunListener构造的,然后EventPublishingRunListener构造:
publicEventPublishingRunListener(SpringApplicationapplication,String[]args){
this.application=application;
this.args=args;
this.initialMulticaster=newSimpleApplicationEventMulticaster();
for(ApplicationListener<?
>listener:
application.getListeners()){
this.initialMulticaster.addApplicationListener(listener);
}
}
最后在构造ApplicationStartedEvent时传给它的基类EventObject的protected不可序列化属性source。
实例化ApplicationStartedEvent后instance.getClass()并包装为ResolvableType类型以保存类型信息,并将它和event作为参数传入SimpleApplicationEventMulticaster的multicastEvent方法。
multicastEvent首先获取ApplicationListener,使用getApplicationListeners方法,这个方法中抛开对listener做了一些缓存类工作外,主要就是将事件和对应的监听器做了下是否支持的验证,返回通过了retrieveApplicationListeners中通过了supportsEvent验证的监听器集合,这里就体现出了ResolvableType的作用,它保存了类型的信息同时对泛型类型也支持。
得到了这些匹配的监听器后,判断当前Executor是否被设置过,如果为null则同步循环执行所有:
invokeListener(listener,event);如果不为null则:
executor.execute(newRunnable(){
@Override
publicvoidrun(){
invokeListener(listener,event);
}
});
监听器执行的时候也会先判断是否是该由自己处理的事件,例如:
@Override
publicvoidonApplicationEvent(ApplicationEventevent){
if(eventinstanceofApplicationEnvironmentPreparedEvent){
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent)event);
}
if(eventinstanceofApplicationPreparedEvent){
onApplicationPreparedEvent(event);
}
}
监听启动后,只准备一些启动参数,和环境变量prepareEnvironment方法先是读取了应用的启动参数和profile配置,然后用listeners.environmentPrepared(environment)传给监听器:
publicvoidenvironmentPrepared(ConfigurableEnvironmentenvironment){
this.initialMulticaster.multicastEvent(newApplicationEnvironmentPreparedEvent(
this.application,this.args,environment));
}
接着判断如果environment是org.springframework.web.context.ConfigurableWebEnvironment的实例,但webEnvironment不是true,也就是说存在org.springframework.web.context.ConfigurableWebEnvironmen但不存在javax.servlet.Servlet的情况,会多执行一步environment=convertToStandardEnvironment(environment)转换。
之后的printBanner就不细说了,如果你在resource下自定义了一个banner.txt文件,启动时会输出内容,否则输出:
._________
/\\/___'_____(_)______\\\(()\___|'_|'_||'_\/_`|\\\\\/___)||_)|||||||(_||))))
'|____|.__|_||_|_||_\__,|////
=========|_|==============|___/=/_/_/_/
:
:
SpringBoot:
:
(v1.4.3.RELEASE)
接着创建ConfigurableApplicationContext实例,方法也很简单,如果是web环境就BeanUtils.instantiate一个org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext的实例并强转为ConfigurableApplicationContext,否则用org.springframework.context.annotation.AnnotationConfigApplicationContext的实例强转。
创建FailureAnalyzers实例,记录了ConfigurableApplicationContext实例中需要关注的部分,如果启动出错了可以据此分析,可以配置,具体的逻辑依然是老方法spring.factories:
不同的Analyzer关注不同的部分,自己可以扩展配置,最后prepareFailureAnalyzers方法给所有Analyzer实例setBeanFactory(context.getBeanFactory()),一旦启动过程进入catch,被注册的Analyzer实例的analyze方法就会被触发执行,分析结果会被loggedExceptions.add(exception)加入到抛出的异常中:
privateFailureAnalysisanalyze(Throwablefailure,List<FailureAnalyzer>analyzers){
for(FailureAnalyzeranalyzer:
analyzers){
FailureAnalysisanalysis=analyzer.analyze(failure);
if(analysis!
=null){
returnanalysis;
}
}
returnnull;
}
例如:
NoSuchBeanDefinitionFailureAnalyzer
@Override
protectedFailureAnalysisanalyze(ThrowablerootFailure,
NoSuchBeanDefinitionExceptioncause,Stringdescription){
if(cause.getNumberOfBeansFound()!
=0){
returnnull;
}
List<AutoConfigurationResult>autoConfigurationResults=getAutoConfigurationResults(
cause);
StringBuildermessage=newStringBuilder();
message.append(String.format("%srequired%sthatcouldnotbefound.%n",
description==null?
"Acomponent":
description,
getBeanDescription(cause)));
if(!
autoConfigurationResults.isEmpty()){
for(AutoConfigurationResultprovider:
autoConfigurationResults){
message.append(String.format("\t-%s%n",provider));
}
}
Stringaction=String.format("Consider%s%sinyourconfiguration.",
(!
autoConfigurationResults.isEmpty()
?
"revisitingtheconditionsaboveordefining":
"defining"),
getBeanDescription(cause));
returnnewFailureAnalysis(message.toString(),action,cause);
}
prepareContext方法中postProcessApplicationContext会在this.beanNameGenerator存在的情况下加载自定义命名策略,然后在this.resourceLoader存在的情况下为context设置resourceLoader和classLoader。
applyInitializers方法调用之前加载的Initializer的实例并执行其initialize方法,例如加载环境变量信息、注册EmbeddedServletContainerInitializedEvent的监听、注册CachingMetadataReaderFactoryPostProcessor等。
listeners.contextPrepared(context)由于EventPublishingRunListener的contextPrepared是空的,先不说了。
logStartupInfo部分初始化了logger,然后根据配置情况打印了启动或运行以及profile是否配置的日志:
protectedvoidlogStartupInfo(booleanisRoot){
if(isRoot){
newStartupInfoLogger(this.mainApplicationClass)
.logStarting(getApplicationLog());
}
}
protectedLoggetApplicationLog(){
if(this.mainApplicationClass==null){
returnlogger;
}
returnLogFactory.getLog(this.mainApplicationClass);
}
publicvoidlogStarting(Loglog){
Assert.notNull(log,"Logmustnotbenull");
if(log.isInfoEnabled()){
log.info(getStartupMessage());
}
if(log.isDebugEnabled()){
log.debug(getRunningMessage());
}
}
protectedvoidlogStartupProfileInfo(ConfigurableApplicationContextcontext){
Loglog=getApplicationLog();
if(log.isInfoEnabled()){
String[]activeProfiles=context.getEnvironment().getActiveProfiles();
if(ObjectUtils.isEmpty(activeProfiles)){
String[]defaultProfiles=context.getEnvironment().getDefaultProfiles();
log.info("Noactiveprofileset,fa