SpringBoot启动流程及自动配置

这篇具有很好参考价值的文章主要介绍了SpringBoot启动流程及自动配置。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SpringBoot启动流程源码:
1、启动SpringBoot启动类SpringbootdemoApplication中的main方法。

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

2、调用SpringApplication.run(SpringbootdemoApplication.class, args),该方法是一个静态方法。

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

3、继续调用SpringApplication内部的run方法

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

,且构建了一个SpringApplication对象,应用程序将从指定的主要来源加载Bean

public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   //resourceLoader赋值为Null
   this.resourceLoader = resourceLoader;
   //primarySources不为空,继续向下执行。为空抛异常
   Assert.notNull(primarySources, "PrimarySources must not be null");
   //将SpringbootdemoApplication(启动类)赋值给primarySources 
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   //从classpath类路径推断Web应用类型,有三种Web应用类型,分别是
   //NONE: 该应用程序不应作为 Web 应用程序运行,也不应启动嵌入式 Web 服务器
   //SERVLET: 该应用程序应作为基于 servlet 的 Web 应用程序运行,并应启动嵌入式 servlet Web 服务器。
   //REACTIVE: 该应用程序应作为响应式 Web 应用程序运行,并应启动嵌入式响应式 Web 服务器
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   //初始化bootstrapRegistryInitializers,通过getSpringFactoriesInstances()获取工厂实例,
   //底层使用的是反射Class<?> instanceClass = ClassUtils.forName(name, classLoader)动态加载实例对象。
   this.bootstrapRegistryInitializers = new ArrayList<>(
         getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
   //初始化ApplicationContextInitializer集合
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   //初始化ApplicationListener
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   //获取StackTraceElement数组遍历,通过反射获取堆栈中有main方法的类。
   this.mainApplicationClass = deduceMainApplicationClass();
}

4、运行 Spring 应用程序,创建并刷新一个新的 ApplicationContext。

public ConfigurableApplicationContext run(String... args) {
   long startTime = System.nanoTime();
   //通过BootstrapRegistryInitializer来initialize默认的DefaultBootstrapContext
   DefaultBootstrapContext bootstrapContext = createBootstrapContext();
   ConfigurableApplicationContext context = null;
   //配置java.awt.headless属性
   configureHeadlessProperty();
   //获取SpringApplicationRunListeners监听器
   SpringApplicationRunListeners listeners = getRunListeners(args);
   //启动SpringApplicationRunListeners监听,表示SpringApplication启动(触发ApplicationStartingEvent事件)
   listeners.starting(bootstrapContext, this.mainApplicationClass);
   try {
      //创建ApplicationArguments对象,封装了args参数
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //做相关环境准备,绑定到SpringApplication,返回可配置环境对象ConfigurableEnvironment 
      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
      //配置spring.beaninfo.ignore,设置为true.即跳过搜索Bean信息
      configureIgnoreBeanInfo(environment);
      //控制台打印SpringBoot的Banner(横幅)标志
      Banner printedBanner = printBanner(environment);
      //根据WebApplicationType从ApplicationContextFactory工厂创建ConfigurableApplicationContext
      context = createApplicationContext();
      //设置ConfigurableApplicationContext中的ApplicationStartup为DefaultApplicationStartup
      context.setApplicationStartup(this.applicationStartup);
      //应用所有的ApplicationContextInitializer容器初始化器初始化context,触发ApplicationContextInitializedEvent事件监听,打印启动日志信息,启动Profile日志信息。
      //ConfigurableListableBeanFactory中注册单例Bean(springApplicationArguments),并为该BeanFactory中的部分属性赋值。
      //加载所有的source.并将Bean加载到ConfigurableApplicationContext,触发ApplicationPreparedEvent事件监听
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
      //刷新容器(在方法中集成了Web容器具体请看 https://editor.csdn.net/md/?articleId=123136262)
      refreshContext(context);
      //刷新容器的后置处理(空方法)
      afterRefresh(context, applicationArguments);
      //启动花费的时间
      Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
      if (this.logStartupInfo) {
         //打印日志Started xxx in xxx seconds (JVM running for xxxx)
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
      }
      //触发ApplicationStartedEvent事件监听。上下文已刷新,应用程序已启动。
      listeners.started(context, timeTakenToStartup);
      //调用ApplicationRunner和CommandLineRunner
      callRunners(context, applicationArguments);
   }
   //处理运行时发生的异常,触发ApplicationFailedEvent事件监听
   catch (Throwable ex) {
      handleRunFailure(context, ex, listeners);
      throw new IllegalStateException(ex);
   }
   try {
      //启动准备消耗的时间
      Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
      //在run方法完成前立即触发ApplicationReadyEvent事件监听,表示应用上下文已刷新,并且CommandLineRunners和ApplicationRunners已被调用。
      listeners.ready(context, timeTakenToReady);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

SpringBoot的自动配置:

SpringBoot的启动类上总是有@SpringBootApplication这个注解。接下来我们来了解一下这个注解。进入@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注解是一个组合注解,由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan注解组成。
@SpringBootConfiguration其实就是一个@Configuration,表明这是一个配置类,可以向容器注入组件。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
 	......
}

@EnableAutoConfiguration由@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})注解组成

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
   ......
}

@AutoConfigurationPackage内部用到了@Import导入Registrar

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
  ......
}

Registrar实现了ImportBeanDefinitionRegistrar接口,因此可将组件都扫描注冊到 spring 容器中

static class Registrar implements ImportBeanDefinitionRegistrar,
DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new
AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new
String[0]));
}
public Set determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}

@AutoConfigurationPackage将主配置类(@SpringBootApplication
标注的类)所在包下的所有组件都扫描注册到Spring容器中。

@Import({AutoConfigurationImportSelector.class}) 将AutoConfigurationImportSelector(自动配置导入选择器)导入容器中

AutoConfigurationImportSelector类中的selectImports()方法的作用是选择导入过滤后的自动配置

 public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

getAutoConfigurationEntry(AnnotationMetadata
annotationMetadata)根据annotationMetadata(即我们的启动类SpringbootdemoApplication)获取AutoConfigurationEntry

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            //获取注解属性
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //从META-INF/spring.factories中获取候选配置。
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //去除重复配置
            configurations = this.removeDuplicates(configurations);
            //获取注解中的排除项
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            //检查排除类
            this.checkExcludedClasses(configurations, exclusions);
            //从上面的候选配置中移除所有排除的配置类
            configurations.removeAll(exclusions);
            //通过ConfigurationClassFilter筛选配置
            configurations = this.getConfigurationClassFilter().filter(configurations);
            //触发自动配置导入事件
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            //返回排除后的自动配置Entry
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

总结SpringBoot启动原理

1、调用有@SpringBootApplication注解的启动类的main方法
2、通过调用SpringApplication内部的run()方法构建SpringApplication对象。
创建SpringApplication对象:
2.1 PrimarySources 不为空,将启动类赋值给primarySources 对象。
2.2 从classpath类路径推断Web应用类型,有三种Web应用类型NONE、SERVLET、REACTIVE
2.3 初始化bootstrapRegistryInitializers
2.4 初始化ApplicationContextInitializer集合
2.5 初始化ApplicationListener
2.6 获取StackTraceElement数组遍历,通过反射获取堆栈中有main方法A的。 3、调用SpringBootApplication的run方法。 4、long startTime = System.nanoTime();
记录项目启动时间。 5、通过BootstrapRegistryInitializer来初始化DefaultBootstrapContext
6、getRunListeners(args)获取SpringApplicationRunListeners监听器 7、
listeners.starting()触发ApplicationStartingEvent事件
8、prepareEnvironment(listeners, bootstrapContext,
applicationArguments) 将配置文件读取到容器中,返回ConfigurableEnvironment 对象。
9、printBanner(environment) 打印Banner图,即SpringBoot启动时的图案。
10、根据WebApplicationType从ApplicationContextFactory工厂创建ConfigurableApplicationContext,并设置ConfigurableApplicationContext中的ApplicationStartup为DefaultApplicationStartup
11、
调用prepareContext()初始化context等,打印启动日志信息,启动Profile日志信息,并为BeanFactory中的部分属性赋值。
12、刷新容器,在该方法中集成了Tomcat容器 13、加载SpringMVC.
14、刷新后的方法,空方法,给用户自定义重写afterRefresh() 15、Duration timeTakenToStartup =
Duration.ofNanos(System.nanoTime() - startTime)算出启动花费的时间。
16、打印日志Started xxx in xxx seconds (JVM running for xxxx)
17、listeners.started(context,
timeTakenToStartup)触发ApplicationStartedEvent事件监听。上下文已刷新,应用程序已启动。
18、调用ApplicationRunner和CommandLineRunner 19、返回上下文。文章来源地址https://www.toymoban.com/news/detail-619766.html

到了这里,关于SpringBoot启动流程及自动配置的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot学习随笔-第一个SpringBoot项目快速启动(org.springframework.boot、@SpringBootApplication、application.yml)

    学习视频:【编程不良人】2021年SpringBoot最新最全教程 创建第一个Module 环境要求 jdk1.8+ maven3.2+ Spring Framework 5.x+ Tomcat 9.0+ IDEA 2021 自动保存刷新pom 在resources下添加application.yml文件后,即可启动springboot应用 由于tomcat内嵌在springboot里面了,所以我们在修改端口号等设置也在配置

    2024年02月05日
    浏览(44)
  • 【Spring Boot】SpringBoot 优雅整合Swagger Api 自动生成文档

    Swagger 是一套 RESTful API 文档生成工具,可以方便地生成 API 文档并提供 API 调试页面。 而 Spring Boot 是一款非常优秀的 Java Web 开发框架,它可以非常方便地构建 Web 应用程序。 在本文中,我们将介绍如何使用 Swagger 以及如何在 Spring Boot 中整合 Swagger 。 首先,在 pom.xml 文件中添

    2023年04月22日
    浏览(34)
  • Springboot启动原理和自动配置原理

    关于 springboot 启动流程和配置原理 很久就写了,不过没有详细补充 ,现在补充 —— 2023-08-05 BootstrapRegistryInitializer 是一个函数是接口 org.springframework.boot.BootstrapRegistry 接口 getSpringFactoriesInstances 加载工厂中组件实现方式 org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFacto

    2023年04月25日
    浏览(32)
  • Spring Boot项目在Windows上的自启动策略与Windows自动登录配置

    🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐 🌊 《100天精通Golang(基础入门篇)》学会Golang语言

    2024年02月07日
    浏览(39)
  • 【SpringBoot应用篇】Spring Boot 配置HTTP 响应内容压缩

    5、默认情况下,要执行压缩,响应的长度至少为 2048 字节,可以通过 server.compression.min-response-size 属性配置。 6、默认情况下,仅当响应的内容类型为以下内容之一时,才会对其进行压缩,可以通过 mime-types 属性配置:text/html,text/xml,text/plain,text/css,text/javascript,application/javasc

    2024年02月16日
    浏览(35)
  • 【Spring Boot】以博客管理系统举例,完整表述SpringBoot从对接Vue到数据库的流程与结构。

    博客管理系统是一个典型的前后端分离的应用,其中前端使用Vue框架进行开发,后端使用Spring Boot框架进行开发,数据库使用MySQL进行存储。下面是从对接Vue到数据库的完整流程和结构。 对接Vue 在前端Vue应用中,需要访问后端Spring Boot应用的REST API接口,与其进行数据交互。具

    2024年02月11日
    浏览(32)
  • Spring(8) Springboot自动配置原理

    Springboot 的自动配置原理,是Springboot中最高频的一道面试题,也是Springboot框架最核心的思想。 首先我们看一张我总结的自动配置原理概览图: 下面,我们就根据这张图详细描述一下具体过程: 首先,我们来看一段代码: 上面就是一段普通的 Springboot 引导类代码,这里有一

    2024年02月12日
    浏览(31)
  • 拆解Spring boot:Springboot为什么如此丝滑而简单?源码剖析解读自动装配

    🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 《Spring 狂野之旅:从入门到入魔》 🚀 本专栏带你从Spring入门到入魔   这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.csdn

    2024年03月23日
    浏览(33)
  • SpringBoot+jasypt-spring-boot-starter实现配置文件明文加密

    springboot:2.1.4.RELEASE JDK:8 jasypt-spring-boot-starter:3.0.2 Jasypt默认算法为PBEWithMD5AndDES,该算法需要一个加密密钥,可以在应用启动时指定(环境变量)。也可以直接写入配置文件 3.1 application.properties配置文件版 加密后,可删除jasypt.encryptor.password配置;发版时可在命令行中配置 3.2 函数

    2024年02月15日
    浏览(29)
  • Spring Boot Testing: 使用springboot-test提供的测试框架来实现自动化测试

    作者:禅与计算机程序设计艺术 软件测试是在开发过程中不可缺少的一环。单元测试、集成测试、功能测试等都是为了保证系统的质量而进行的测试活动。单元测试主要验证各个模块(类、方法)在各种情况下是否正常工作;集成测试则是将不同模块组合起来看是否可以正常

    2024年02月07日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包