SpringBoot启动流程源码2:运行程序

本文详细解析了Spring Boot应用程序的启动流程,从run()方法入手,深入探讨了IOC容器的创建、环境配置、组件扫描与加载等关键步骤,以及ApplicationRunner和CommandLineRunner的执行时机。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

run()方法(运行程序)

public ConfigurableApplicationContext run(String... args) {
   //开始和停止的监听
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   //声明一个IOC容器,暂时为空,后面创建
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   //与awt应用相关的
   configureHeadlessProperty();
   
   //获取SpringApplicationRunListeners 
   //详见注释1
   SpringApplicationRunListeners listeners = getRunListeners(args);
   //回调所有的获取SpringApplicationRunListener.starting()方法 
   listeners.starting();
   try {
      //封装命令行参数 
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //准备环境
      //详见注释2
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
      //打印控制台springboot图标
      Banner printedBanner = printBanner(environment);

      //创建ApplicationContext,IOC容器
      //详见注释3
      context = createApplicationContext();
      
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      
      //准备所有
      //详见注释4
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      
      //刷新容器;IOC容器初始化(如果是web应用还会创建嵌入式的Tomcat)     
      //扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
      refreshContext(context);

      //从IOC容器中获取所有的ApplicationRunner和CommandLineRunner
      //详见注释5
      afterRefresh(context, applicationArguments);
      //所有的SpringApplicationRunListener回调finished方法       
      listeners.finished(context, null); 
      return context;
}

注释

1.getRunListeners():

Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
      getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));

通过getSpringFactoriesInstances获取,也是从类路径下META‐INF/spring.factories找

2.prepareEnvironment():

//获取或创建环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境
configureEnvironment(environment, applicationArguments.getSourceArgs())
//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成 
listeners.environmentPrepared(environment);

3.createApplicationContext():

//判断当前应用环境来创建对应的IOC容器
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
   try {
      switch (this.webApplicationType) {
      case SERVLET:
         contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
         break;
      case REACTIVE:
         contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
         break;
      default:
         contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
      }
   }
}

4.prepareContext():

//将environment保存到IOC中
context.setEnvironment(environment);
//IOC容器后置处理(注册一些组件)
postProcessApplicationContext(context);

//回调之前创建SpringApplication对象时保存的所有的ApplicationContextInitializer的initialize()方法 
applyInitializers(context);
	//applyInitializers代码片段:
	for (ApplicationContextInitializer initializer : getInitializers()) {
   	Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
        ApplicationContextInitializer.class);
   	Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
   	initializer.initialize(context);

//回调之前创建SpringApplication对象时保存的所有的listeners的contextPrepared()方法
listeners.contextPrepared(context);
	//contextPrepared代码片段:
	for (SpringApplicationRunListener listener : this.listeners) {
   	listener.contextPrepared(context);

//日志记录
if (this.logStartupInfo) {
   logStartupInfo(context.getParent() == null);
   logStartupProfileInfo(context);
}

//注册命令行参数对象
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
//注册打印的图标
if (printedBanner != null) {
   beanFactory.registerSingleton("springBootBanner", printedBanner);
}
//获取主配置类
Set<Object> sources = getAllSources();
//prepareContext运行完成以后回调所有的listeners的contextLoaded(); 
listeners.contextLoaded(context);

5.afterRefresh()里的callRunners():

//从IOC容器中获取所有的ApplicationRunner和CommandLineRunner
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
//ApplicationRunner优先级大于CommandLineRunner
for (Object runner : new LinkedHashSet<>(runners)) {
   if (runner instanceof ApplicationRunner) {
      callRunner((ApplicationRunner) runner, args);
   }
   if (runner instanceof CommandLineRunner) {
      callRunner((CommandLineRunner) runner, args);
   }
}

不同版本spring boot源码略有差距

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值