SpringBoot整个启动过程的分析
前言
前一篇分析了springboot如何启动以及内置web容器,这篇我们一起看一下springboot的整个启动过程,废话不多说,正文开始。
正文
一、springboot的启动类是**application,以注解@springbootapplication注明。
@springbootapplication public class cmsapplication { public static void main(string[] args) { springapplication.run(cmsapplication.class, args); } }
springbootapplication注解是@configuration,@enableautoconfiguration,@componentscan三个注解的集成,分别表示springbean的配置bean,开启自动配置spring的上下文,组件扫描的路径,这也是为什么*application.java需要放在根路径的原因,这样@componentscan扫描的才是整个项目。
二、该启动类默认只有一个main方法,调用的是springapplication.run方法,下面我们来看一下springapplication这个类。
public static configurableapplicationcontext run(object source, string... args) { return run(new object[]{source}, args); } ... public static configurableapplicationcontext run(object[] sources, string[] args) { return (new springapplication(sources)).run(args);//sources为具体的cmsapplication.class类 } ...
抽出其中两个直接调用的run方法,可以看出静态方法springapplication.run最终创建了一个springapplication,并运行其中run方法。
查看起构造方法:
public springapplication(object... sources) { this.bannermode = mode.console; this.logstartupinfo = true; this.addcommandlineproperties = true; this.headless = true; this.registershutdownhook = true; this.additionalprofiles = new hashset(); this.initialize(sources); } ...
构造方法设置了基础值后调用initialize方法进行初始化,如下:
private void initialize(object[] sources) { if (sources != null && sources.length > 0) { this.sources.addall(arrays.aslist(sources)); } this.webenvironment = this.deducewebenvironment(); this.setinitializers(this.getspringfactoriesinstances(applicationcontextinitializer.class)); this.setlisteners(this.getspringfactoriesinstances(applicationlistener.class)); this.mainapplicationclass = this.deducemainapplicationclass(); } ...
初始化方法主要做了几步:
1.将source放入springapplication的sources属性中管理,sources是一个linkedhashset()
,这意味着我们可以同时创建多个自定义不重复的application,但是目前只有一个。
2.判断是否是web程序(javax.servlet.servlet
和org.springframework.web.context.configurablewebapplicationcontext
都必须在类加载器中存在),并设置到webenvironment
属性中。
3.从spring.factories中找出applicationcontextinitializer并设置到初始化器initializers。
4.从spring.factories中找出applicationlistener,并实例化后设置到springapplication的监听器listeners属性中。这个过程就是找出所有的应用程序事件监听器。
5.找出的main方法的类(这里是cmsapplication),并返回class对象。
默认情况下,initialize方法从spring.factories文件中找出的key为applicationcontextinitializer的类有:
- org.springframework.boot.context.config.delegatingapplicationcontextinitializer
- org.springframework.boot.context.contextidapplicationcontextinitializer
- org.springframework.boot.context.configurationwarningsapplicationcontextinitializer
- org.springframework.boot.context.web.serverportinfoapplicationcontextinitializer
- org.springframework.boot.autoconfigure.logging.autoconfigurationreportlogginginitializer
key为applicationlistener的有:
- org.springframework.boot.context.config.configfileapplicationlistener
- org.springframework.boot.context.config.ansioutputapplicationlistener
- org.springframework.boot.logging.loggingapplicationlistener
- org.springframework.boot.logging.classpathloggingapplicationlistener
- org.springframework.boot.autoconfigure.backgroundpreinitializer
- org.springframework.boot.context.config.delegatingapplicationlistener
- org.springframework.boot.builder.parentcontextcloserapplicationlistener
- org.springframework.boot.context.fileencodingapplicationlistener
- org.springframework.boot.liquibase.liquibaseservicelocatorapplicationlistener
三、springapplication构造和初始化完成后,便是运行其run方法
public configurableapplicationcontext run(string... args) { stopwatch stopwatch = new stopwatch();// 构造一个任务执行观察器 stopwatch.start();// 开始执行,记录开始时间 configurableapplicationcontext context = null; failureanalyzers analyzers = null; this.configureheadlessproperty(); // 获取springapplicationrunlisteners,内部只有一个eventpublishingrunlistener springapplicationrunlisteners listeners = this.getrunlisteners(args); // 封装成springapplicationevent事件然后广播出去给springapplication中的listeners所监听,启动监听 listeners.starting(); try { // 构造一个应用程序参数持有类 applicationarguments applicationarguments = new defaultapplicationarguments(args); // 加载配置环境 configurableenvironment environment = this.prepareenvironment(listeners, applicationarguments); banner printedbanner = this.printbanner(environment); // 创建spring容器(使用beanutils.instantiate) context = this.createapplicationcontext(); // 若容器创建失败,分析输出失败原因 new failureanalyzers(context); // 设置容器配置环境,监听等 this.preparecontext(context, environment, listeners, applicationarguments, printedbanner); // 刷新容器 this.refreshcontext(context); this.afterrefresh(context, applicationarguments); // 广播出applicationreadyevent事件给相应的监听器执行 listeners.finished(context, (throwable)null); stopwatch.stop();// 执行结束,记录执行时间 if (this.logstartupinfo) { (new startupinfologger(this.mainapplicationclass)).logstarted(this.getapplicationlog(), stopwatch); } return context;// 返回spring容器 } catch (throwable var9) { this.handlerunfailure(context, listeners, (failureanalyzers)analyzers, var9); throw new illegalstateexception(var9); } }
run方法过程分析如上,该方法几个关键步骤如下:
1.创建了应用的监听器springapplicationrunlisteners并开始监听
2.加载springboot配置环境(configurableenvironment),如果是通过web容器发布,会加载standardenvironment,其最终也是继承了configurableenvironment,类图如下
可以看出,*environment最终都实现了propertyresolver接口,我们平时通过environment对象获取配置文件中指定key对应的value方法时,就是调用了propertyresolver接口的getproperty方法。
3.配置环境(environment)加入到监听器对象中(springapplicationrunlisteners)
4.创建spring容器:configurableapplicationcontext(应用配置上下文),我们可以看一下创建方法
protected configurableapplicationcontext createapplicationcontext() { class<?> contextclass = this.applicationcontextclass; if (contextclass == null) { try { contextclass = class.forname(this.webenvironment ? "org.springframework.boot.context.embedded.annotationconfigembeddedwebapplicationcontext" : "org.springframework.context.annotation.annotationconfigapplicationcontext"); } catch (classnotfoundexception var3) { throw new illegalstateexception("unable create a default applicationcontext, please specify an applicationcontextclass", var3); } } return (configurableapplicationcontext)beanutils.instantiate(contextclass); }
方法会先获取显式设置的应用上下文(applicationcontextclass),如果不存在,再加载默认的环境配置(通过是否是web environment判断),默认选择annotationconfigapplicationcontext注解上下文(通过扫描所有注解类来加载bean),最后通过beanutils实例化上下文对象,并返回,configurableapplicationcontext类图如下
主要看其继承的两个方向:
- lifecycle:生命周期类,定义了start启动、stop结束、isrunning是否运行中等生命周期空值方法
- applicationcontext:应用上下文类,其主要继承了beanfactory(bean的工厂类)。
5.回到run方法内,设置容器preparecontext方法,将listeners、environment、applicationarguments、banner等重要组件与上下文对象关联
6.刷新容器,refresh()
方法,初始化方法如下:
public void refresh() throws beansexception, illegalstateexception { object var1 = this.startupshutdownmonitor; synchronized(this.startupshutdownmonitor) { this.preparerefresh(); configurablelistablebeanfactory beanfactory = this.obtainfreshbeanfactory(); this.preparebeanfactory(beanfactory); try { this.postprocessbeanfactory(beanfactory); this.invokebeanfactorypostprocessors(beanfactory); this.registerbeanpostprocessors(beanfactory); this.initmessagesource(); this.initapplicationeventmulticaster(); this.onrefresh(); this.registerlisteners(); this.finishbeanfactoryinitialization(beanfactory); this.finishrefresh(); } catch (beansexception var9) { if (this.logger.iswarnenabled()) { this.logger.warn("exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroybeans(); this.cancelrefresh(var9); throw var9; } finally { this.resetcommoncaches(); } } }
refresh()
方法做了很多核心工作比如beanfactory的设置,beanfactorypostprocessor接口的执行、beanpostprocessor接口的执行、自动化配置类的解析、spring.factories的加载、bean的实例化、条件注解的解析、国际化的初始化等等。这部分内容会在之后的文章中分析。
7.广播出applicationreadyevent,执行结束返回configurableapplicationcontext。
至此,springboot启动完成,回顾整体流程,springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationcontext),并基于以上条件,在容器中开始实例化我们需要的bean。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接