根据springboot启动(1)的分析,springboot真正启动从应用主类main方法开始,其run方法中由SpringApplication完成真正启动。
- 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应用的lambda方法(默认web应用)
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
- 创建应用上下文工厂,用于自动装配等(默认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文件获取监听配置并创建监听器
- 配置应用启动类
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);
}
}
- 监听器发布应用开始启动
- 获取应用配置:ConfigurableEnvironment(包含logger、应用环境、应用参数等)
- 创建应用上下文:createApplicationContext
默认AnnotationConfigServletWebServerApplicationContext,读取配置环境、加载监听,构造资源加载器reader、pacakge scanner,构造bean工厂加载器。 - 启动前准备工作:prepareContext
通过bean工厂生产所需bean,配置各类资源 - 刷新上下文:refreshContext
自动装配springboot配置组件(如mybatis等),创建web server(如tomcat)。 - 再刷新上下文(空实现留作扩展)
- 发布启动完成事件
- 自动装配
自动装配在AbstractApplicationContext.refresh中完成的,由invokeBeanFactoryPostProcessors方法执行自动装配链条。
- 获取bean工厂加载器、资源加载器
- 资源加载器读取spring.factories配置文件,获取待加载bean及其全路径
- 通过反射获取待加载bean的class对象和构造方法
- 实例化所有待加载bean,并加入spring容器
上述3个步骤就是springboot启动大致流程,前期主要完成配置环境读取、加载监听器、构造工厂加载器合和资源加载器。其中核心是在刷新上下文refreshContext,包含了web server的启动和自动装备。
自动装配流程:
- @EnableAutoConfiguration模块的
通过自定义@Enable模块驱动测试知道,springboot通过@ImportSelector等注解类,实现bean的实例化和注入。@EnableAutoConfiguration同样的实现原理,其ImportSelector接口方法实现中会扫描项目下的spring.factories,获取待加载类。 - 读取各jar包下spring.factories文件的配置内容,该文件结构为:接口=接口实现类列表,比如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模块获取到类后,通过工厂反射实例化待加载类。
在springboot的各功能模块spring.factories文件中配置了大量默认实现接口。再加上springboot的条件装配,通过配置文件实现配置的功能模块。比如,springboot中包含了mongodb的实现MongoTemplate,只需要在配置文件中添加mongodb的依赖,就能在自动装配接的完成mongodb服务MongoTemplate的加载。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
springboot这种带有默认实现的配置方式,体现了其“规约大于配置”的思想,用户开箱即用,极大提高了开发效率。