根據(jù)springboot啟動(dòng)(1)的分析昆雀,springboot真正啟動(dòng)從應(yīng)用主類(lèi)main方法開(kāi)始湿酸,其run方法中由SpringApplication完成真正啟動(dòng)陷虎。
- new SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
- 配置是否為web應(yīng)用的lambda方法(默認(rèn)web應(yīng)用)
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
- 創(chuàng)建應(yīng)用上下文工廠递胧,用于自動(dòng)裝配等(默認(rèn)SERVLET囚痴,及支持注解的servlet)
@FunctionalInterface
public interface ApplicationContextFactory {
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch(webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
} catch (Exception var2) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
}
};
- 讀取spring.factories文件獲取監(jiān)聽(tīng)配置并創(chuàng)建監(jiān)聽(tīng)器
- 配置應(yīng)用啟動(dòng)類(lèi)
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
- SpringApplication.run
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
- 監(jiān)聽(tīng)器發(fā)布應(yīng)用開(kāi)始啟動(dòng)
- 獲取應(yīng)用配置:ConfigurableEnvironment(包含logger募寨、應(yīng)用環(huán)境族展、應(yīng)用參數(shù)等)
- 創(chuàng)建應(yīng)用上下文:createApplicationContext
默認(rèn)AnnotationConfigServletWebServerApplicationContext,讀取配置環(huán)境拔鹰、加載監(jiān)聽(tīng)仪缸,構(gòu)造資源加載器reader、pacakge scanner列肢,構(gòu)造bean工廠加載器恰画。 - 啟動(dòng)前準(zhǔn)備工作:prepareContext
通過(guò)bean工廠生產(chǎn)所需bean,配置各類(lèi)資源 - 刷新上下文:refreshContext
自動(dòng)裝配springboot配置組件(如mybatis等)瓷马,創(chuàng)建web server(如tomcat)拴还。 - 再刷新上下文(空實(shí)現(xiàn)留作擴(kuò)展)
- 發(fā)布啟動(dòng)完成事件
- 自動(dòng)裝配
自動(dòng)裝配在AbstractApplicationContext.refresh中完成的,由invokeBeanFactoryPostProcessors方法執(zhí)行自動(dòng)裝配鏈條欧聘。
- 獲取bean工廠加載器片林、資源加載器
- 資源加載器讀取spring.factories配置文件,獲取待加載bean及其全路徑
- 通過(guò)反射獲取待加載bean的class對(duì)象和構(gòu)造方法
- 實(shí)例化所有待加載bean怀骤,并加入spring容器
上述3個(gè)步驟就是springboot啟動(dòng)大致流程费封,前期主要完成配置環(huán)境讀取、加載監(jiān)聽(tīng)器蒋伦、構(gòu)造工廠加載器合和資源加載器弓摘。其中核心是在刷新上下文refreshContext,包含了web server的啟動(dòng)和自動(dòng)裝備凉敲。
自動(dòng)裝配流程:
- @EnableAutoConfiguration模塊的
通過(guò)自定義@Enable模塊驅(qū)動(dòng)測(cè)試知道衣盾,springboot通過(guò)@ImportSelector等注解類(lèi),實(shí)現(xiàn)bean的實(shí)例化和注入爷抓。@EnableAutoConfiguration同樣的實(shí)現(xiàn)原理势决,其ImportSelector接口方法實(shí)現(xiàn)中會(huì)掃描項(xiàng)目下的spring.factories,獲取待加載類(lèi)蓝撇。 - 讀取各jar包下spring.factories文件的配置內(nèi)容果复,該文件結(jié)構(gòu)為:接口=接口實(shí)現(xiàn)類(lèi)列表,比如mongodb的jar包下
org.springframework.data.web.config.SpringDataJacksonModules=org.springframework.data.mongodb.config.GeoJsonConfiguration
org.springframework.data.repository.core.support.RepositoryFactorySupport=org.springframework.data.mongodb.repository.support.MongoRepositoryFactory
- @EnableAutoConfiguration模塊獲取到類(lèi)后渤昌,通過(guò)工廠反射實(shí)例化待加載類(lèi)虽抄。
在springboot的各功能模塊spring.factories文件中配置了大量默認(rèn)實(shí)現(xiàn)接口走搁。再加上springboot的條件裝配,通過(guò)配置文件實(shí)現(xiàn)配置的功能模塊迈窟。比如私植,springboot中包含了mongodb的實(shí)現(xiàn)MongoTemplate,只需要在配置文件中添加mongodb的依賴(lài)车酣,就能在自動(dòng)裝配接的完成mongodb服務(wù)MongoTemplate的加載曲稼。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
springboot這種帶有默認(rèn)實(shí)現(xiàn)的配置方式,體現(xiàn)了其“規(guī)約大于配置”的思想湖员,用戶開(kāi)箱即用贫悄,極大提高了開(kāi)發(fā)效率。