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 */ publicstaticList loadFactoryNames(Class>factoryType,@NullableClassLoaderclassLoader){ StringfactoryTypeName=factoryType.getName(); returnloadSpringFactories(classLoader).getOrDefault(factoryTypeName,Collections.emptyList()); } /** *加载spring.factories文件的核心实现 */ privatestaticMap >loadSpringFactories(@NullableClassLoaderclassLoader){ //先从缓存获取,如果获取到了说明之前已经被加载过 MultiValueMap result=cache.get(classLoader); if(result!=null){ returnresult; } try{ //找到所有jar中的spring.factories文件的地址 Enumeration urls=(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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。