当前位置: 首页 > news >正文

[4-06-09].第10节:自动配置- 分析@SpringBootApplication启动类

SpringBoot学习大纲


一、启动类加载器@SpringBootApplication:

1.1.@SpringBootApplication注解源码:

  • 1.@SpringBootApplication注解是引导加载自动配置类
  • 2.@SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan()
    在这里插入图片描述
  • 3.下面依次介绍@SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan()这3个注解

1.2.注解1:分析@SpringBootConfiguration注解

  • 1.根据@SpringBootConfiguration注解的源码可以看到,在源码中有注解@Configuration,出现了@Configuration,就代表当前类是一个配置类
  • 2.也就是说在SpringBoot项目中mainApplication这个程序也是SpringBoot中的一个配置类
    在这里插入图片描述

1.3.注解2:分析@ComponentScan注解:

  • 1.@ComponentScan代表的就是包扫描
    在这里插入图片描述
  • 2.@ComponentScan("com.jianqun"):可以设置包扫描路径
  • 3.如果有多个包,就可以写成数组的形式,如@SpringBootApplication(scanBasePackages = {"com.jianqun",“xx.cc.ddd”)}或者也可以使用@ComponentScan ()指定扫描路径

1.4.注解3:分析@EnableAutoConfiguration注解:

a.功能:

  • 1.@EnableAutoConfiguration注解是用于开启自动配置的核心,有了这个注解,就可以使得 spring-boot-autoconfigure下官方写好的所有配置类生效

b.源码

  • 1.在@EnableAutoConfiguration注解的源码中可看到:@EnableAutoConfiguration = @AutoConfigurationPackage + @Import()
    在这里插入图片描述

  • 2.下面的内容分别来分析 @AutoConfigurationPackage和@Import()注解在自动配置中的原理


c.分析 @EnableAutoConfiguration --> @AutoConfigurationPackage:


注解 @AutoConfigurationPackage的 源码

  • 1.功能:@AutoConfigurationPackage 就是自动配置包,它用于指定默认的包规则
    在这里插入图片描述
  • 2.在@AutoConfigurationPackage 注解的源码中又包括了@import注解
    在这里插入图片描述
  • 3.通过源码,可以看到使用@import注解给容器导入了名称是AutoConfigurationPackages.Registar组件,那AutoConfigurationPackages.Registar是什么???就需要分析AutoConfigurationPackages.Registar源码了

AutoConfigurationPackages.Registrar源码分析:

  • 1.通过下图中的Registrar源码可以看到包含了两个方法,分别是registerBeanDefinitions()方法determineImports()方法
    在这里插入图片描述
  • 2.方法1分析:对于registerBeanDefinitions(参数1,参数2)方法,它传递了两个参数;
    在这里插入图片描述
    • 对于参数1: AnnotationMetadata metadata,第一个参数意思是传递的是注解的元信息
      • 这里所指的注解是:@AutoConfigurationPackage,代表的就是这个注解标在哪个位置,都有哪些属性的元信息;
      • 这个注解是标在了MainApplication这个类位置上; 当元信息拿来后,用new PackageImports(metadata).getPackageNames()获取到包名称,然后toArray(new String[0])转封装成数组
        在这里插入图片描述
      • 最后register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]))代码的意思就是 把某MainApplication这个包里面的所有组件批量注册到容器中
        在这里插入图片描述

总结: @AutoConfigurationPackage作用:

  • 作用1是:指定了默认包规则
  • 作用2是:把默认包路径下的所有组件注册到容器中,即把 启动类MainApplication这个包里面的所有组件批量注册到容器中了

d.分析 @EnableAutoConfiguration --> @Import(AutoConfigurationImportSelector.class)


@Import(AutoConfigurationImportSelector.class)作用

  • 1.这里的@Import(AutoConfigurationImportSelector.class)注解是批量导入组件的作用,可以使用程序来定义导入的一堆组件,把这些类的全类名加载进来,最终实现组件的批量导入
    在这里插入图片描述
  • 2.具体是怎么批量导入这些组件的????就需要分析AutoConfigurationImportSelector的源码了,看看具体是怎么把全类名加载进来实现组件批量导入

定位AutoConfigurationImportSelector的源码

  • 1.下图为AutoConfigurationImportSelector类的源码
    在这里插入图片描述
  • 2.在AutoConfigurationImportSelector类的源码中可以看到:主要包括了selectImports(AnnotationMetadata annotationMetadata)等方法
    在这里插入图片描述

分析selectImports(AnnotationMetadata annotationMetadata)方法源码

  • 1.从selectImports(AnnotationMetadata annotationMetadata)方法的源码中,可以看到返回值是一个字符串数组类型的。在这个返回的数组中存储的就是那些需要导入到容器中那一堆组件
    在这里插入图片描述
  • 2.那返回的数组中存储的那一堆组件是怎么来的呢??那就需要分析源码中的getAutoConfigurationEntry(annotationMetadata)方法了!!
    在这里插入图片描述

分析selectImports(参数) 方法中的getAutoConfigurationEntry(annotationMetadata)方法源码

  • 1.如下是getAutoConfigurationEntry(annotationMetadata)方法的源码:
    在这里插入图片描述
  • 2.在源码中可以看到:List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes),通过调用 getCandidateConfigurations()方法用于获取到那些需要导入到容器中的那一堆组件
    在这里插入图片描述
  • 3.如下debugger中可以看出configurations变量一共存储的131个组件,这131个组件就是需要导入容器中的
    在这里插入图片描述

分析getCandidateConfiguration()源码:

  • 1.点击getCandidateConfiguration() 方法,进入方法内部:
    在这里插入图片描述
  • getCandidateConfiguration()方法在SpringBoot2和SpringBoot3中的实现方式有了变化!!!!下面对此分别进行分析

============== 分析getCandidateConfiguration()方法在SpringBoot2中的实现 ------------ 开始 ==============

  • 1、getCandidateConfiguration() 方法源码
    • getCandidateConfiguration() 方法中利用了Spring的工厂加载器SpringFactoriesLoader.loadFactoryNames()又加载了一些东西,加载的这些就是上面List中存储的那131个组件
      在这里插入图片描述
    • 2.具体这些组件loadFactoryNames()方法时怎么加载来的就需要分析SpringFactoriesLoader.loadFactoryNames()方法的源码了
  • 2、SpringFactoriesLoader.loadFactoryNames()方法的源码
    • 如下是loadFactoryNames()方法的源码:
      在这里插入图片描述
    • SpringFactoriesLoader.loadFactoryNames()这个方法中的源码中可以看到,通过调用了loadSpringFactories()方法来获取这一堆要加载的组件
      在这里插入图片描述
    • 那loadSpringFactories()方法具体具体是从哪里得到的这一堆要注入容器的组件呢???? 那就要具体分析loadSpringFactories()方法的源码了
  • 3、loadSpringFactories()源码分析:
    • 通过源码分析,可以看到通过loadSpringFactories()方法,得到所有要加载的组件,返回值是Map<String, List<String>>类型的
      在这里插入图片描述
    • 可以从源码中看到lassLoader.getResources()方法会从META-INF/spring.factories位置来加载一个文件,默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
      在这里插入图片描述
    • 比较核心的jar包,即spring-boot-autoconfigure-2.5.2.RELEASE.jar包,在它的里面也有META-INF/spring.factories
      在这里插入图片描述
    • 最终可以看出,在配置文件spring.factories中写死了spring-boot一启动就要给容器中加载的所有配置类xxxxAutoConfiguration
    • 虽然所有的自动配置类在springboot启动的时候都加载了,但还是按照条件配置规则(@ConditionalOnxxx)来进行启动,只有条件成立,才能生效,最终实现了按需配置

============== 分析getCandidateConfiguration()方法在SpringBoot2中的实现 ------------ 结束 ==============


============== 分析getCandidateConfiguration()方法在SpringBoot3中的实现 ------------ 开始 ==============

  • 1、getCandidateConfiguration()方法源码:
    • getCandidateConfiguration() 方法中利用ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())又加载了一些东西,这些就是List中存储的那一堆药加载的组件
    • 这一堆要加载的组件具体是怎么加载进来的,就要分析ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())源码了
      在这里插入图片描述
  • 2、ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())源码
    • 在load()方法的源码中,代码annotation.getName()是获取到注解的全类名,然后在META-INF/spring/%s.imports中,对%s进行替换
      在这里插入图片描述
    • 在这里,annotation.getName()的值是:org.springframework.boot.autoconfigure,对s%进行替换后是:META-INF/spring/org.springframework.boot.autoconfigure.imports,也就是说SpringBoot在底层就会加载导入META-INF/spring/org.springframework.boot.autoconfigure.imports定义的所有类,一共有142个,这就实现了组件的批量导入
      在这里插入图片描述
      ============== 分析getCandidateConfiguration()方法在SpringBoot3中的实现 ------------ 结束 ==============

总结:

  • 1.对于SpringBoot2版本的项目在启动的时候,利用注解@Import(AutoConfigurationImportSelector.class)在底层实际上是从位置为 META-INF/spring.factories位置批量导入一堆组件
  • 2.对于SpringBoot3版本的项目在启动的时候,利用注解@Import(AutoConfigurationImportSelector.class)在底层实际上是从位置为 META-INF/spring/org.springframework.boot.xxxx.imports 中导入一堆组件
  • 3.不论是SpringBoot2还是SpringBoot3每个自动配置类按照条件进行生效

二、自动配置流程:

2.1.定位xxxxAutoConfiguration位置:

  • 1.引入开发所需要的场景启动器后,就会导入相关场景的所有依赖 -> 每个场景启动器都引入了一个spring-boot-starter,这个是核心场景启动器 -> 核心场景启动器引入了spring-boot-autoconfigure包
    在这里插入图片描述
  • 2.spring-boot-autoconfigure里面包含了所有场景的所有配置
    在这里插入图片描述
  • 3.在所有场景的配置中,都有xxxxAutoConfiguration自动配置类:
    在这里插入图片描述

2.2.总结:

  • SpringBoot先加载所有的自动配置类
  • 每个自动配置类都是按照条件进行生效的
  • 生效的配置类就会给容器中装配很多个组件
  • 只要容器中有这些组件,就相当于这些功能就具有了

三、属性绑定:

3.1.分析@EnableConfigurationProperties(ServerProperties.class):

  • 1.每个自动配置类都可能有注解@EnableConfigurationProperties(ServerProperties.class),用来把配置文件中配的指定前缀的属性值封装到 xxxProperties属性类中
  • 2.在容器中使用@Bean放一堆组件

3.2.举例:

  • 1.以Tomcat为例:把服务器的所有配置都是以server开头的,配置都封装到了属性类中
    在这里插入图片描述
    在这里插入图片描述
  • 2.给容器中放的所有组件的一些核心参数,都来自于xxxProperties。xxxProperties都是和配置文件绑定,只需要改配置文件的值,核心组件的底层参数都能修改

四、自定义类绑定配置提示:

4.1.自定义类:

在这里插入图片描述


4.2.配置绑定:

a.问题描述:

  • 我们在配置文件与自定义类绑定到额时候,没有任何提示,不是很友好,我们需要引入依赖进行解决

b.引入依赖:

在这里插入图片描述

c.测试:

在这里插入图片描述


五、总结SpringBoot开发时的核心流程:

  • 1.导入starter,就会导入autoconfigure包
  • 2.autoconfigure 包里面 有一个文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,里面指定的所有启动要加载的自动配置类
  • 3.@EnableAutoConfiguration 会自动的把上面文件里面写的所有自动配置类都导入进来
  • 4.然后xxxAutoConfiguration 回按照条件注解进行按需加载
  • 5.xxxAutoConfiguration给容器中导入一堆组件,组件都是从 xxxProperties中提取属性值,xxxProperties又是和配置文件进行了绑定
    在这里插入图片描述

http://www.xdnf.cn/news/214579.html

相关文章:

  • github使用记录
  • Redis分布式锁使用以及对接支付宝,paypal,strip跨境支付
  • 第十六届蓝桥杯大赛网安组--几道简单题的WP
  • HTTP协议重定向及交互
  • 运放参数汇总
  • mac word接入deepseek
  • LVGL -窗口操作
  • Linux/AndroidOS中进程间的通信线程间的同步 - 管道和FIFO
  • 【C++编程入门】:基本语法
  • Java 多线程基础:Thread 类详解
  • 云数据中心整体规划方案PPT(113页)
  • VIT(ICLR2021)
  • foc控制 - clarke变换和park变换
  • 【后端】【Docker】 Docker 动态代理 取消代理完整脚本合集(Ubuntu)
  • 内网服务器映射到公网上怎么做?网络将内网服务转换到公网上
  • 学习基本宠物美容
  • 零基础实现把知识库接到聆思CSK6大模型开发板上
  • 请简述一下什么是 Kotlin?它有哪些特性?
  • C++ 红黑树
  • 第14讲:科研图表的导出与排版艺术——高质量 PDF、TIFF 输出与投稿规范全攻略!
  • Java 基础--运算符全解析
  • Ubuntu搭建 Nginx以及Keepalived 实现 主备
  • ‘WebDriver‘ object has no attribute ‘find_element_by_class‘
  • 咖啡的功效与作用及副作用,咖啡对身体有哪些好处和坏处
  • 什么是缓冲区溢出?NGINX是如何防止缓冲区溢出攻击的?
  • [逆向工程]什么是CPU寄存器(三)
  • Qt开发之C++泛型编程进阶
  • C语言教程(二十五):C 语言函数可变参数详解
  • 机器学习-入门-决策树(1)
  • 大模型微调之LLaMA-Factory 系列教程大纲