springboot启动过程(2)-run方法

本文详细解析了Spring Boot项目的启动流程,从SpringApplication的run方法入手,介绍了如何创建Spring容器,包括配置环境、打印Banner、创建上下文及刷新容器等关键步骤。

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

1 springApplication的run

run方法主要是用于创造spring容器ConfigurableApplicationContext对象。

public ConfigurableApplicationContext run(String... args) {
  StopWatch stopWatch = new StopWatch(); // 构造一个任务执行观察器
  stopWatch.start(); // 开始执行,记录开始时间
  ConfigurableApplicationContext context = null;
  configureHeadlessProperty();
  // 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
  SpringApplicationRunListeners listeners = getRunListeners(args);
  // 会封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听
  // 这里接受ApplicationStartedEvent事件的listener会执行相应的操作
  listeners.started();
  try {
  // 构造一个应用程序参数持有类
  ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

  //创建并配置环境
  ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
  
  //输出banner
   Banner printedBanner = printBanner(environment);
  context = createApplicationContext();
  analyzers = new FailureAnalyzers(context);
  prepareContext(context, environment, listeners, applicationArguments,printedBanner);
  refreshContext(context);
  afterRefresh(context, applicationArguments);
  listeners.finished(context, null);
  stopWatch.stop();
  if (this.logStartupInfo) {
  new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  }
  return context;
  }
  catch (Throwable ex) {
  // 这个过程报错的话会执行一些异常操作、然后广播出ApplicationFailedEvent事件给相应的监听器执行
  handleRunFailure(context, listeners, ex); 
  throw new IllegalStateException(ex);
  }
}

2 run的过程

按顺序看run,发现执行了下面这些过程。

(1 )stopWatch 记录开始结束时间,configureHeadlessProperty 设置headless模式,
	awt的headless,一般运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能。
(2)springApplicationListeners: 这个类包含了SpringApplicationRunlistener的集合和一个日志类。
	SpringApplicationRunlistener也是通过spring.factories加载,如下可以看到,
	就包含一种EventPublishingRunListener。
  org.springframework.boot.SpringApplicationRunListener=\
  org.springframework.boot.context.event.EventPublishingRunListener
  
  EventPublishingRunListener通过看源码,
  发现包含了started environmentPrepared contextPrepared contextLoaded
  等方法,基本都是包装特定event并发event。配合run函数的代码如下,可以得知,
  springApplicationListeners主要负责在run函数的各个阶段,发起事件。
  比如在创建spring容器的前后调用了start和finish方法,在创建容器时,
  把listener当参数传入便于在各个时间发起事件。

(3)prepareEnvironment  创建并设置环境 

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners
,ApplicationArguments applicationArguments) {
  // Create and configure the environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    listeners.environmentPrepared(environment);
    if (isWebEnvironment(environment) && !this.webEnvironment) {
      environment = convertToStandardEnvironment(environment);
    }
    return environment;
  }

     如上,设置环境分几个步骤,getOrderCreateEnvironment获得一个标准环境对象StandardEnvironment,
     然后configureEnvironment进行配置。其中configureEnvironment 包含两个配置,
     configurePropertySources和configureProfiles两个方法。Environment代表程序运行环境,
     包含两种信息,一个是profiles,描述各种bean defination,另一种是properties描述系统配置,
     包括配置文件 jvm属性文件 环境变量等。configureEnvironment方法先是
     调用configurePropertySources来配置properties,然后调用configureProfiles来配置profiles。
     然后listener发出事件。
(4)pringBnner 打印banner,打印banner信息,即启动时出现的logo信息。
(5)createApplicationContext 
 
创建spring容器。如果是web程序,
那么造
org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
容器,

否则构造
org.springframework.context.annotation.AnnotationConfigApplicationContext
容器
(6)prepareContext    
首先调用了postProcessApplicationContext(context),如果是web程序并且是spring web容器,
那么设置实例命名生成器并注册,同时注册资源加载器并注册。然后调用applyInitializers(context),
遍历每个初始化器,调用相应的innitialize方法让初始化器开始工作。
  (7)refreshContext(context) 
  刷新spring容器,内部做很多事情,包括springFactory设置,BeanFactoryPostProcessor接口执行,
  BeanPostProcessor接口执行,自动化配置类解析,条件注解解析,国际化的初始化等。

(8)afterRefresh  
调用了 callRunners,主要是得到所有的CommonandLineRunner和ApplicationRunner, 
使用 @Order(value=x)设置排序值,可以支持自定义runner完成自己需求。

private void callRunners(ApplicationContext context, ApplicationArguments args) {
 List<Object> runners = new ArrayList<Object>();
   // 找出Spring容器中ApplicationRunner接口的实现类
  runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
  // 找出Spring容器中CommandLineRunner接口的实现类
  runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
  // 对runners进行排序
  AnnotationAwareOrderComparator.sort(runners);
  // 遍历runners依次执行
   for (Object runner : new LinkedHashSet<Object>(runners)) {
  // 如果是ApplicationRunner,进行ApplicationRunner的run方法调用
    if (runner instanceof ApplicationRunner) {
      callRunner((ApplicationRunner) runner, args);
    }
  // 如果是CommandLineRunner,进行CommandLineRunner的run方法调用
  if (runner instanceof CommandLineRunner) {
      callRunner((CommandLineRunner) runner, args);
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值