[Spring Boot]-Spring Boot启动过程

143 阅读3分钟

1.Spring Boot版本


本文章使用的Spring Boot版本:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.7.4</version>
</parent>

2.流程图


springboot启动过程流程.png

3.Spring Boot启动类

@SpringBootApplication
public class SpringbootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemoApplication.class, args);
    }
}

通常我们是通过Spring Boot启动类的main方法启动Spring Boot程序,我们通过main方法就能梳理出Spring Boot在启动过程中都做了哪些事情。

3.1.SpringApplication构造器

/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified primary sources (see {@link SpringApplication class-level}
 * documentation for details). The instance can be customized before calling
 * {@link #run(String...)}.
 * @param resourceLoader the resource loader to use
 * @param primarySources the primary bean sources
 * @see #run(Class, String[])
 * @see #setSources(Set)
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   // 设置web application的类型
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   // 设置bootstrapRegistryInitializers
   this.bootstrapRegistryInitializers = new ArrayList<>(
         getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   // 设置入口类
   this.mainApplicationClass = deduceMainApplicationClass();
}

通过代码可以看到在设置Initializers和Listeners的过程中使用getSpringFactoriesInstances()方法,我们来看下具体是如何执行的。

3.1.1.getSpringFactoriesInstances()

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
   ClassLoader classLoader = getClassLoader();
   // Use names and ensure unique to protect against duplicates
   // 从META-INF/spring.factories中获取对应的className
   Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
   // 使用反射创建实例
   List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
   AnnotationAwareOrderComparator.sort(instances);
   return instances;
}

1). 从META-INF/spring.factories中获取对应的className

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    Map<String, List<String>> result = (Map)cache.get(classLoader);
    if (result != null) {
        return result;
    } else {
        Map<String, List<String>> result = new HashMap();

        try {
            Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");

            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                // 代码省略
                }
            cache.put(classLoader, result);
            return result;
        } catch (IOException var14) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
        }
    }
}

2). 使用反射创建实例

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
      ClassLoader classLoader, Object[] args, Set<String> names) {
   List<T> instances = new ArrayList<>(names.size());
   for (String name : names) {
      try {
         Class<?> instanceClass = ClassUtils.forName(name, classLoader);
         Assert.isAssignable(type, instanceClass);
         Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
         T instance = (T) BeanUtils.instantiateClass(constructor, args);
         instances.add(instance);
      }
      catch (Throwable ex) {
         throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
      }
   }
   return instances;
}

3.2.SpringApplication的run方法

/**
 * Run the Spring application, creating and refreshing a new
 * {@link ApplicationContext}.
 * @param args the application arguments (usually passed from a Java main method)
 * @return a running {@link ApplicationContext}
 */
public ConfigurableApplicationContext run(String... args) {
   long startTime = System.nanoTime();
   // 创建DefaultBootstrapContext
   // 并执行启动初始程序方法(BootstrapRegistryInitializer.initialize())
   DefaultBootstrapContext bootstrapContext = createBootstrapContext();
   ConfigurableApplicationContext context = null;
   // 设置java.awt.headless,可忽略
   configureHeadlessProperty();
   // META-INF/spring.factories获取SpringApplicationRunListener
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // 发布ApplicationStartingEvent事件,并记录步骤
   listeners.starting(bootstrapContext, this.mainApplicationClass);
   try {
       // 封装入参
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      // 准备环境
      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
      // 设置system.property中的属性spring.beaninfo.ignore
      configureIgnoreBeanInfo(environment);
      // 打印Banner
      Banner printedBanner = printBanner(environment);
      // 创建AnnotationConfigServletWebServerApplicationContext
      // TODO
      context = createApplicationContext();
      context.setApplicationStartup(this.applicationStartup);
      // 准备上下文
      // 1.环境配置设置到上下文
      // 2.执行ApplicationContext后置处理,设置beanName生成器,设置资源加载器
      // 3.执行初始化程序,运行ApplicationContextInitializer.initialize()方法
      // 4.发布ApplicationContextInitializedEvent事件
      // 5.bootstrapContext发布BootstrapContextClosedEvent事件
      // 6.注册bean对象springApplicationArguments
      // 7.注册bean对象springBootBanner
      // 8.设置不可循环依赖,设置可以重写BeanDefinition
      // 9.添加懒加载的BeanFactory后置处理器
      // 10.注册主函数为bean
      // 11.发布ApplicationPreparedEvent事件
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
      // 刷新
      // 此处直接调用spring框架中AbstractApplicationContext的refresh()方法
      // TODO
      refreshContext(context);
      // 刷新之后的操作
      afterRefresh(context, applicationArguments);
      Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
      }
      // 发布ApplicationStartedEvent事件
      listeners.started(context, timeTakenToStartup);
      // 启动完成回调
      // 1.找到所有ApplicationRunner的子类
      // 2.找到所有CommandLineRunner的子类
      // 3.回调执行所有找到的子类的run方法
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, listeners);
      throw new IllegalStateException(ex);
   }
   try {
      Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
      listeners.ready(context, timeTakenToReady);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

4.总结


5.更新时间


创建时间:2022/11/10 好文分享:Spring容器启动流程(源码解读)-敖丙