SpringBoot超详细分析启动流程

 更新时间:2022年07月04日 10:39:10   作者:喜欢小苹果的码农  
今天小编就为大家分享一篇关于SpringBoot整个启动过程的分析,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

Springboot启动类

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

SpringBootApplication注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

@SpringBootApplication注解上标注了@EnableAutoConfiguration,表示TestApplication是引导类。

Springboot的启动方法中传入了两个参数,引导类,和程序参数。

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
   return run(new Class<?>[] { primarySource }, args);
}

调用run方法

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   return new SpringApplication(primarySources).run(args);
}

run方法中有两步,创建SpringApplication和执行SpringApplication的run方法。

1、创建SpringApplication

SpringApplication的构造器

public SpringApplication(Class<?>... primarySources) {
   this(null, primarySources);
}
private ResourceLoader resourceLoader;
private Set<Class<?>> primarySources;
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   //将resourceLoader赋值成员变量,此处是null
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
    //将引导类赋值成员变量
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //判断web类型,赋值成员变量
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   //加载初始化器
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //加载监听器
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //获得引导类
   this.mainApplicationClass = deduceMainApplicationClass();
}

1.1、判断web类型

//org.springframework.boot.WebApplicationType#deduceFromClasspath
static WebApplicationType deduceFromClasspath() {
    //WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
//JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
   if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
         && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      return WebApplicationType.REACTIVE;
   }
    //SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" }
   for (String className : SERVLET_INDICATOR_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
         return WebApplicationType.NONE;
      }
   }
   return WebApplicationType.SERVLET;
}

1.2、加载上下文初始化器

利用spi加载 ApplicationContextInitializer 的实现类

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
   return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    //获取classloader
   ClassLoader classLoader = getClassLoader();
   // Use names and ensure unique to protect against duplicates
    //获取配置文件中接口实现类的全限定名
   Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //初始化
   List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
   AnnotationAwareOrderComparator.sort(instances);
    //返回
   return instances;
}
public ClassLoader getClassLoader() {
   if (this.resourceLoader != null) {
      return this.resourceLoader.getClassLoader();
   }
   return ClassUtils.getDefaultClassLoader();
}
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;
}

将初始化好的上下文初始化器设置到成员变量

//private List<ApplicationContextInitializer<?>> initializers;
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
   this.initializers = new ArrayList<>(initializers);
}

1.3、加载监听器

将初始化好的监听器设置到成员变量

//private List<ApplicationListener<?>> listeners;
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
   this.listeners = new ArrayList<>(listeners);
}

1.4、获得引导类类型

private Class<?> deduceMainApplicationClass() {
   try {
      StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
      for (StackTraceElement stackTraceElement : stackTrace) {
         //获取main方法的类
         if ("main".equals(stackTraceElement.getMethodName())) {
            return Class.forName(stackTraceElement.getClassName());
         }
      }
   }
   catch (ClassNotFoundException ex) {
      // Swallow and continue
   }
   return null;
}

2、执行SpringApplication的run方法启动Springboot

public ConfigurableApplicationContext run(String... args) {
    //启动停止监听器
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
    //Spring上下文
   ConfigurableApplicationContext context = null;
    //错误导出
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
    //运行时监听器
   SpringApplicationRunListeners listeners = getRunListeners(args);
    //启动运行时监听器
   listeners.starting();
   try {
       //生成ApplicationArguments
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
       //准备environment
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
       //打印banner
      Banner printedBanner = printBanner(environment);
       //创建Spring上下文
      context = createApplicationContext();
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
       //准备上下文
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
       //刷新上下文
      refreshContext(context);
       //上下文刷新后
      afterRefresh(context, applicationArguments);
       //停止 停止监听器
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
       //停止运行时监听器
      listeners.started(context);
       //执行回调
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }
   try {
      listeners.running(context);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

2.1、准备environment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   // Create and configure the environment
    //创建environment
   ConfigurableEnvironment environment = getOrCreateEnvironment();
    //配置environment
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   ConfigurationPropertySources.attach(environment);
   listeners.environmentPrepared(environment);
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
            deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);
   return environment;
}

2.1.1、创建environment

private ConfigurableEnvironment getOrCreateEnvironment() {
   if (this.environment != null) {
      return this.environment;
   }
   switch (this.webApplicationType) {
   case SERVLET:
      return new StandardServletEnvironment();
   case REACTIVE:
      return new StandardReactiveWebEnvironment();
   default:
      return new StandardEnvironment();
   }
}

这里根据web类型创建不同的environment

2.1.2、配置environment

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
   if (this.addConversionService) {
       //转换服务
      ConversionService conversionService = ApplicationConversionService.getSharedInstance();
      environment.setConversionService((ConfigurableConversionService) conversionService);
   }
   configurePropertySources(environment, args);
   configureProfiles(environment, args);
}

配置PropertySources

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
   MutablePropertySources sources = environment.getPropertySources();
   if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
      sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
   }
   if (this.addCommandLineProperties && args.length > 0) {
      String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
      if (sources.contains(name)) {
         PropertySource<?> source = sources.get(name);
         CompositePropertySource composite = new CompositePropertySource(name);
         composite.addPropertySource(
               new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
         composite.addPropertySource(source);
         sources.replace(name, composite);
      }
      else {
         sources.addFirst(new SimpleCommandLinePropertySource(args));
      }
   }
}

主要为了在PropertySources添加一个SimpleCommandLinePropertySource。

配置profiles

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
   Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
   profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
   environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}

将profile添加到environment

2.2、打印Banner

private Banner.Mode bannerMode = Banner.Mode.CONSOLE;
private Banner printBanner(ConfigurableEnvironment environment) {
   //无需打印
   if (this.bannerMode == Banner.Mode.OFF) {
      return null;
   }
   ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
         : new DefaultResourceLoader(getClassLoader());
   SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
   if (this.bannerMode == Mode.LOG) {
      return bannerPrinter.print(environment, this.mainApplicationClass, logger);
   }
   return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

2.3、创建Spring上下文

//DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."			//+"web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
//DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."	//+"boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
//DEFAULT_CONTEXT_CLASS = "org.springframework.context."
//			+ "annotation.AnnotationConfigApplicationContext";
protected ConfigurableApplicationContext createApplicationContext() {
   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);
         }
      }
      catch (ClassNotFoundException ex) {
         throw new IllegalStateException(
               "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
      }
   }
    //初始化上下文并返回
   return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

2.4、准备上下文

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
      SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
   context.setEnvironment(environment);
    //ApplicationContext的后置处理
   postProcessApplicationContext(context);
    //应用初始化器
   applyInitializers(context);
    //运行时监听器的准备上下文监听
   listeners.contextPrepared(context);
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }
   // Add boot specific singleton beans
    //获取beanFactory
   ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    //将程序入参注册bean springApplicationArguments
   beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    //将banner注册bean springBootBanner
   if (printedBanner != null) {
      beanFactory.registerSingleton("springBootBanner", printedBanner);
   }
    //设置BeanDefinition是否允许重写
   if (beanFactory instanceof DefaultListableBeanFactory) {
      ((DefaultListableBeanFactory) beanFactory)
            .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
    //初始化允许懒加载,设置BeanfactorypostProcessor
   if (this.lazyInitialization) {
      context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
   }
   // Load the sources
    //获取source
   Set<Object> sources = getAllSources();
   Assert.notEmpty(sources, "Sources must not be empty");
   load(context, sources.toArray(new Object[0]));
    //运行时监听器,上下文加载完成
   listeners.contextLoaded(context);
}

2.4.1、ApplicationContext的后置处理

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    //注册 beanNameGenerator
   if (this.beanNameGenerator != null) {
      context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
            this.beanNameGenerator);
   }
    //注册 resourceLoader
   if (this.resourceLoader != null) {
      if (context instanceof GenericApplicationContext) {
         ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
      }
      if (context instanceof DefaultResourceLoader) {
         ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
      }
   }
    //设置 ConversionService
   if (this.addConversionService) {
      context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
   }
}
//org.springframework.boot.convert.ApplicationConversionService#getSharedInstance
public static ConversionService getSharedInstance() {
   ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
   if (sharedInstance == null) {
      synchronized (ApplicationConversionService.class) {
         sharedInstance = ApplicationConversionService.sharedInstance;
         if (sharedInstance == null) {
            sharedInstance = new ApplicationConversionService();
            ApplicationConversionService.sharedInstance = sharedInstance;
         }
      }
   }
   return sharedInstance;
}

2.4.2、应用初始化器

protected void applyInitializers(ConfigurableApplicationContext context) {
   for (ApplicationContextInitializer initializer : getInitializers()) {
      Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
            ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      initializer.initialize(context);
   }
}

执行所有实现了 ApplicationContextInitializer 接口的类的initialize方法。

2.4.3、获取sources

public Set<Object> getAllSources() {
   Set<Object> allSources = new LinkedHashSet<>();
   if (!CollectionUtils.isEmpty(this.primarySources)) {
      allSources.addAll(this.primarySources);
   }
   if (!CollectionUtils.isEmpty(this.sources)) {
      allSources.addAll(this.sources);
   }
   return Collections.unmodifiableSet(allSources);
}

这里组装了引导类和自定义的source

2.4.4、加载

protected void load(ApplicationContext context, Object[] sources) {
   if (logger.isDebugEnabled()) {
      logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
   }
    //创建BeanDefinitionLoader
   BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
   if (this.beanNameGenerator != null) {
      loader.setBeanNameGenerator(this.beanNameGenerator);
   }
   if (this.resourceLoader != null) {
      loader.setResourceLoader(this.resourceLoader);
   }
   if (this.environment != null) {
      loader.setEnvironment(this.environment);
   }
    //加载,spring的逻辑,这里会将引导类注册
   loader.load();
}
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
   return new BeanDefinitionLoader(registry, sources);
}

2.5、刷新上下文

private void refreshContext(ConfigurableApplicationContext context) {
   refresh(context);
   if (this.registerShutdownHook) {
      try {
          //注册钩子	关闭SpringBoot容器
         context.registerShutdownHook();
      }
      catch (AccessControlException ex) {
         // Not allowed in some environments.
      }
   }
}

刷新

protected void refresh(ApplicationContext applicationContext) {
   Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    //执行spring容器的刷新
   ((AbstractApplicationContext) applicationContext).refresh();
}

2.6、上下文刷新后

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

这里是一个空实现,应该是作为模板扩展吧。

2.7、执行回调

private void callRunners(ApplicationContext context, ApplicationArguments args) {
   List<Object> runners = new ArrayList<>();
   runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
   runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
   AnnotationAwareOrderComparator.sort(runners);
   for (Object runner : new LinkedHashSet<>(runners)) {
      if (runner instanceof ApplicationRunner) {
         callRunner((ApplicationRunner) runner, args);
      }
      if (runner instanceof CommandLineRunner) {
         callRunner((CommandLineRunner) runner, args);
      }
   }
}

这里会调用所有实现了ApplicationRunner,CommandLineRunner的接口的实现类的run方法。

到此这篇关于SpringBoot超详细分析启动流程的文章就介绍到这了,更多相关SpringBoot启动分析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot整合Redis实现刷票过滤功能

    SpringBoot整合Redis实现刷票过滤功能

    随着互联网的不断发展,网站或APP的用户流量增加,也衍生出了一些恶意刷量等问题,给数据分析及运营带来极大的困难,所以本文使用SpringBoot和Redis实现一个刷票过滤功能,需要的可以参考一下
    2023-06-06
  • SSH框架网上商城项目第16战之Hibernate二级缓存处理首页热门显示

    SSH框架网上商城项目第16战之Hibernate二级缓存处理首页热门显示

    这篇文章主要介绍了SSH框架网上商城项目第16战之Hibernate的二级缓存处理首页的热门显示,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • java使用apache commons连接ftp修改ftp文件名失败原因

    java使用apache commons连接ftp修改ftp文件名失败原因

    这篇文章主要介绍了java使用apache commons连接ftp修改ftp文件名失败原因解析,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • Java并发编程之栅栏(CyclicBarrier)实例介绍

    Java并发编程之栅栏(CyclicBarrier)实例介绍

    这篇文章主要介绍了Java并发编程之栅栏(CyclicBarrier)实例介绍,栅栏类似闭锁,但是它们是有区别的,需要的朋友可以参考下
    2015-04-04
  • eclipse汉化及jdk安装环境配置超详细教程(Java安装教程)

    eclipse汉化及jdk安装环境配置超详细教程(Java安装教程)

    这篇文章主要介绍了eclipse汉化及jdk安装环境配置超详细教程(Java安装教程),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • java多线程-同步块实例讲解

    java多线程-同步块实例讲解

    本文主要介绍java多线程-同步块的知识,这里整理了相关的详细资料及简单示例代码,有兴趣的小伙伴可以参考下
    2016-09-09
  • 详谈ServiceLoader实现原理

    详谈ServiceLoader实现原理

    下面小编就为大家带来一篇详谈ServiceLoader实现原理。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • springboot打war包部署到外置tomcat容器的方法

    springboot打war包部署到外置tomcat容器的方法

    这篇文章主要介绍了springboot]打war包部署到外置tomcat容器,在这需要注意的是在boot-launch.war在tomcat webapps目录里面解压到boot-launch文件夹,感兴趣的朋友跟随小编一起看看吧
    2022-04-04
  • Java的sort的排序及使用详解

    Java的sort的排序及使用详解

    这篇文章主要为大家详细介绍了Java的sort的排序及使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 ,希望您能够多多关注
    2022-02-02
  • 深入浅析java中flyway使用简介

    深入浅析java中flyway使用简介

    Flyway是独立于数据库的应用、管理并跟踪数据库变更的数据库版本管理工具。这篇文章主要介绍了flyway使用简介,需要的朋友可以参考下
    2020-07-07

最新评论