springboot启动过程一.docx

上传人:b****5 文档编号:8334773 上传时间:2023-01-30 格式:DOCX 页数:11 大小:20.15KB
下载 相关 举报
springboot启动过程一.docx_第1页
第1页 / 共11页
springboot启动过程一.docx_第2页
第2页 / 共11页
springboot启动过程一.docx_第3页
第3页 / 共11页
springboot启动过程一.docx_第4页
第4页 / 共11页
springboot启动过程一.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

springboot启动过程一.docx

《springboot启动过程一.docx》由会员分享,可在线阅读,更多相关《springboot启动过程一.docx(11页珍藏版)》请在冰豆网上搜索。

springboot启动过程一.docx

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 数学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1