SpringBoot应用启动过程分析
springboot项目通过springapplication.run(app.class, args)来启动:
@configuration public class app { public static void main(string[] args) { springapplication.run(app.class, args); } }
接下来,通过源码来看看springapplication.run()
方法的执行过程。如果对源码不感兴趣,直接下拉到文章末尾,看启动框图。
1、调用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); }
2、springapplication对象初始化
public springapplication(object... sources) { initialize(sources); } @suppresswarnings({ "unchecked", "rawtypes" }) private void initialize(object[] sources) { if (sources != null && sources.length > 0) { this.sources.addall(arrays.aslist(sources)); } // 判断是否为web环境 this.webenvironment = deducewebenvironment(); // 找到meta-inf/spring.factories中applicationcontextinitializer所有实现类,并将其实例化 setinitializers((collection) getspringfactoriesinstances( applicationcontextinitializer.class)); // 找到meta-inf/spring.factories中applicationlistener所有实现类,并将其实例化 setlisteners((collection) getspringfactoriesinstances(applicationlistener.class)); // 获取当前main方法类对象,即测试类中的app实例 this.mainapplicationclass = deducemainapplicationclass(); }
对象初始化过程中,使用到了getspringfactoriesinstances方法:
private <t> collection<? extends t> getspringfactoriesinstances(class<t> type) { return getspringfactoriesinstances(type, new class<?>[] {}); } private <t> collection<? extends t> getspringfactoriesinstances(class<t> type, class<?>[] parametertypes, object... args) { classloader classloader = thread.currentthread().getcontextclassloader(); // use names and ensure unique to protect against duplicates // 读取meta-inf/spring.factories指定接口的实现类 set<string> names = new linkedhashset<string>( springfactoriesloader.loadfactorynames(type, classloader)); list<t> instances = createspringfactoriesinstances(type, parametertypes, classloader, args, names); annotationawareordercomparator.sort(instances); return instances; } @suppresswarnings("unchecked") private <t> list<t> createspringfactoriesinstances(class<t> type, class<?>[] parametertypes, classloader classloader, object[] args, set<string> names) { list<t> instances = new arraylist<t>(names.size()); for (string name : names) { try { class<?> instanceclass = classutils.forname(name, classloader); assert.isassignable(type, instanceclass); constructor<?> constructor = instanceclass.getconstructor(parametertypes); t instance = (t) constructor.newinstance(args); instances.add(instance); } catch (throwable ex) { throw new illegalargumentexception( "cannot instantiate " + type + " : " + name, ex); } } return instances; } // 读取meta-inf/spring.factories文件 public static list<string> loadfactorynames(class<?> factoryclass, classloader classloader) { string factoryclassname = factoryclass.getname(); try { enumeration<url> urls = (classloader != null ? classloader.getresources(factories_resource_location) : classloader.getsystemresources(factories_resource_location)); list<string> result = new arraylist<string>(); while (urls.hasmoreelements()) { url url = urls.nextelement(); properties properties = propertiesloaderutils.loadproperties(new urlresource(url)); string factoryclassnames = properties.getproperty(factoryclassname); result.addall(arrays.aslist(stringutils.commadelimitedlisttostringarray(factoryclassnames))); } return result; } catch (ioexception ex) { throw new illegalargumentexception("unable to load [" + factoryclass.getname() + "] factories from location [" + factories_resource_location + "]", ex); } }
meta-inf/spring.factories文件内容,spring boot版本1.3.6.release # propertysource loaders org.springframework.boot.env.propertysourceloader=\ org.springframework.boot.env.propertiespropertysourceloader,\ org.springframework.boot.env.yamlpropertysourceloader # run listeners org.springframework.boot.springapplicationrunlistener=\ org.springframework.boot.context.event.eventpublishingrunlistener # application context initializers org.springframework.context.applicationcontextinitializer=\ org.springframework.boot.context.configurationwarningsapplicationcontextinitializer,\ org.springframework.boot.context.contextidapplicationcontextinitializer,\ org.springframework.boot.context.config.delegatingapplicationcontextinitializer,\ org.springframework.boot.context.web.serverportinfoapplicationcontextinitializer # application listeners org.springframework.context.applicationlistener=\ org.springframework.boot.builder.parentcontextcloserapplicationlistener,\ org.springframework.boot.context.fileencodingapplicationlistener,\ org.springframework.boot.context.config.ansioutputapplicationlistener,\ org.springframework.boot.context.config.configfileapplicationlistener,\ org.springframework.boot.context.config.delegatingapplicationlistener,\ org.springframework.boot.liquibase.liquibaseservicelocatorapplicationlistener,\ org.springframework.boot.logging.classpathloggingapplicationlistener,\ org.springframework.boot.logging.loggingapplicationlistener # environment post processors org.springframework.boot.env.environmentpostprocessor=\ org.springframework.boot.cloud.cloudfoundryvcapenvironmentpostprocessor,\ org.springframework.boot.env.springapplicationjsonenvironmentpostprocessor
applicationlistener接口是spring框架的事件监听器,其作用可理解为springapplicationrunlistener发布通知事件时,由applicationlistener负责接收。springapplicationrunlistener接口的实现类就是eventpublishingrunlistener,其在springboot启动过程中,负责注册applicationlistener监听器,在不同时间节点发布不同事件类型,如果有applicationlistener实现类监听了该事件,则接收处理。
public interface springapplicationrunlistener { /** * 通知监听器,springboot开始启动 */ void started(); /** * 通知监听器,环境配置完成 */ void environmentprepared(configurableenvironment environment); /** * 通知监听器,applicationcontext已创建并初始化完成 */ void contextprepared(configurableapplicationcontext context); /** * 通知监听器,applicationcontext已完成ioc配置 */ void contextloaded(configurableapplicationcontext context); /** * 通知监听器,springboot开始完毕 */ void finished(configurableapplicationcontext context, throwable exception); }
附图为applicationlistener监听接口实现类,每个类对应了一种事件。
3、springapplication核心run方法
/** * run the spring application, creating and refreshing a new * {@link applicationcontext}. * @param args the application arguments (usually passed from a java main method) * @return a running {@link applicationcontext} */ public configurableapplicationcontext run(string... args) { // 任务执行时间监听,记录起止时间差 stopwatch stopwatch = new stopwatch(); stopwatch.start(); configurableapplicationcontext context = null; configureheadlessproperty(); // 启动springapplicationrunlistener监听器 springapplicationrunlisteners listeners = getrunlisteners(args); listeners.started(); try { applicationarguments applicationarguments = new defaultapplicationarguments( args); // 创建并刷新applicationcontext context = createandrefreshcontext(listeners, applicationarguments); afterrefresh(context, applicationarguments); // 通知监听器,应用启动完毕 listeners.finished(context, null); stopwatch.stop(); if (this.logstartupinfo) { new startupinfologger(this.mainapplicationclass) .logstarted(getapplicationlog(), stopwatch); } return context; } catch (throwable ex) { handlerunfailure(context, listeners, ex); throw new illegalstateexception(ex); } }
这里,需要看看createandrefreshcontext()方法是如何创建并刷新applicationcontext。
private configurableapplicationcontext createandrefreshcontext( springapplicationrunlisteners listeners, applicationarguments applicationarguments) { configurableapplicationcontext context; // create and configure the environment // 创建并配置运行环境,webenvironment与standardenvironment选其一 configurableenvironment environment = getorcreateenvironment(); configureenvironment(environment, applicationarguments.getsourceargs()); listeners.environmentprepared(environment); if (iswebenvironment(environment) && !this.webenvironment) { environment = converttostandardenvironment(environment); } // 是否打印banner,就是启动程序时出现的图形 if (this.bannermode != banner.mode.off) { printbanner(environment); } // create, load, refresh and run the applicationcontext // 创建、装置、刷新、运行applicationcontext context = createapplicationcontext(); context.setenvironment(environment); postprocessapplicationcontext(context); applyinitializers(context); // 通知监听器,applicationcontext创建完毕 listeners.contextprepared(context); if (this.logstartupinfo) { logstartupinfo(context.getparent() == null); logstartupprofileinfo(context); } // add boot specific singleton beans context.getbeanfactory().registersingleton("springapplicationarguments", applicationarguments); // load the sources // 将beans载入到applicationcontext容器中 set<object> sources = getsources(); assert.notempty(sources, "sources must not be empty"); load(context, sources.toarray(new object[sources.size()])); // 通知监听器,beans载入applicationcontext完毕 listeners.contextloaded(context); // refresh the context refresh(context); if (this.registershutdownhook) { try { context.registershutdownhook(); } catch (accesscontrolexception ex) { // not allowed in some environments. } } return context; }
其中利用createapplicationcontext()来实例化applicationcontext对象,即default_web_context_class 、default_context_class两个对象其中一个。
protected configurableapplicationcontext createapplicationcontext() { class<?> contextclass = this.applicationcontextclass; if (contextclass == null) { try { contextclass = class.forname(this.webenvironment ? default_web_context_class : default_context_class); } catch (classnotfoundexception ex) { throw new illegalstateexception( "unable create a default applicationcontext, " + "please specify an applicationcontextclass", ex); } } return (configurableapplicationcontext) beanutils.instantiate(contextclass); }
postprocessapplicationcontext(context)、applyinitializers(context)
均为初始化applicationcontext工作。
springboot启动过程分析就先到这里,过程中关注几个对象:
applicationcontext:spring高级容器,与beanfactory类似。
springapplicationrunlistener:sprintboot启动监听器,负责向applicationlistener注册各类事件。
environment:运行环境。
4、启动过程框图
5、接口文档
总结
以上所述是小编给大家介绍的springboot应用启动过程分析,希望对大家有所帮助