从一个SpringBoot启动类说起。
@SpringBootApplication public class DemoApplication{ public static void main(Stirng[] args){ SpringApplication.run(DemoApplication.class, args); } }
@SpringBootApplication是以下三个Annotation的复合:
- @Configuration:SpringBoot启动类本身也是一个配置类。
- @EnableAutoConfiguration:作为一个复合Annotation,其定义中最关键的是@Import(AutoConfigurationImportSelector.class),在AutoConfigurationImportSelector类中,通过调用SpringFactoriesLoader的方法从classpath中搜寻所有META-INF/spring.factories配置文件,将其中自动配置项通过反射实例化为对应IoC配置类,然后汇总为一个加载到IoC容器中。
- @ComponentScan:自动扫描并加载符合条件的组件。
SpringBoot应用的启动流程:
1. SpringApplication.run()的运行会创建一个SpringApplication实例,在其初始化时会收集各种条件和回调接口,例如,判断是否为web类型、加载ApplicationContextInitializer和 ApplicationListener(这里用到了SpringFactoriesLoader类的方法)、推断并设置main方法的定义类。以下所有的this指针均指向SpringApplication实例。
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { //... this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
2. 进入run方法的逻辑中,通过SpringFactoriesLoader获得 SpringApplicationRunListeners的实例 listeners (其中封装了一个SpringApplicationRunListener集合),执行listeners.starting(),表示“SpringBoot应用开始执行!”。
SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting();
3. 创建Environment,配置其PropertySorce以及Profile。
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment);
在prepareEnvironment方法中执行了listeners的environmentPrepared方法,表示“SpringBoot应用的Environment准备好了!”。
listeners.environmentPrepared((ConfigurableEnvironment)environment);
4. 创建ApplicationContext,这里会根据用户是否明确设置了applicationContextClass类型以及初始阶段的推断结果,决定当前的ApplicationContext类型。
context = this.createApplicationContext();
配置ApplicationContext。
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
在prepareContext方法中设置了Environment,又调用了ApplicationContextInitializer的initialize方法对已经创建好的context做进一步的处理,然后执行listeners的contextPrepared方法,表示“SpringBoot应用的ApplicationContext准备好了!”。
private void prepareContext(//...) { context.setEnvironment(environment); this.postProcessApplicationContext(context); this.applyInitializers(context); listeners.contextPrepared(context); //... }
5. 最核心的一步:同样是在prepareContext方法中,将之前@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备好的context中,然后执行listeners 的contextLoaded方法,表示“SpringBoot应用的ApplicationContext装填完毕!”。
private void prepareContext(//...) { //... Set<Object> sources = this.getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); this.load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); }
6. 执行refreshContext方法,最终调用的是ApplicationContext的refresh方法,完成IoC容器可用的最后一道工序。另外,这里还判断了一下是否需要添加ShutdownHook。
private void refreshContext(ConfigurableApplicationContext context) { this.refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException var3) { } } }
7. 执行afterRefresh方法,其实什么也没有做。
protected void afterRefresh(//...) { }
8. 执行listeners的started方法,表示“SpringBoot应用已经启动!”。
listeners.started(context);
9. 查找ApplicationContext中是否注册有ApplicationRunner和CommandLineRunner,如果有,则执行它们。
this.callRunners(context, applicationArguments);
private void callRunners(ApplicationContext context, ApplicationArguments args) { //... runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); //... }
10. 正常情况下,到这里就已经完成了 (如果整个过程出现异常,那么会有详细的异常处理类负责检测)。最后还有一个listeners的running方法可以进一步检测容器是否正常。
try { listeners.running(context); return context; } catch (Throwable var9) { //... throw new IllegalStateException(var9); }
整个过程看起来冗长无比,但忽略其中的事件通知等逻辑,那么这个启动过程可以精简为:
- 初始化SpringApplication,收集各种条件和回调接口。
- 创建并配置Environment。
- 创建并初始化ApplicationContext,设置Environment,加载自动配置等。
- 更新ApplicationContext,完成最终程序启动。
原文地址:https://www.cnblogs.com/asleaf/p/12594628.html