SpringBoot学习(9)(springboot自动配置原理)(源码分析、面试题)

news2024/11/15 13:42:22

目录

一、引言

二、为啥学习自动配置原理?

三、自动配置

(1)基本概述

(2)学习回顾

四、自动配置——源码分析

(1)回顾学习

(2)回到源码学习

(1)注解@ComponentScan

(2)注解@SpringBootConfiguration

(3)核心注解@EnableAutoConfiguration

(4)对刚刚源码的一个大致总结(梳理)

五、解决问题

六、分析总结

(1)小总结

(2)面试(总结)

一、引言

  • 之前学习了Bean的扫描、Bean的注册、以及Bean的注册条件。
  • 现在在这篇博客学习springboot的自动配置原理

二、为啥学习自动配置原理?

  • 在实际的开发中,经常会定义一些公共的组件,供大家一起使用。为了使用更加的方便,经常会将这些公共的组件自定义成starter。如果想定义starter,就必须先了解自动配置原理才可以。
  • 应对面试。springboot作为当下市面上最流行的Java技术之一。面试题:请说一下springboot自动配置的原理?

三、自动配置

(1)基本概述
  • 所谓的自动配置。就是遵循约定大约配置的原则,在boot程序启动后,起步依赖中的一些bean对象会自动注入到ioc容器中。
(2)学习回顾
  • 之前学习bean扫描、bean注册、bean注册条件的时候——>其中学习的案例中通过导入一个自定义的jar包,jar包中有两个实体类(Country、Province),然后在自己的boot工程引入了这个jar包。想把Country和Province注入到Ioc容器当中——>自己提供写了一个配置类(CommonConfig),这里面提供了两个方法(country()、province())这两个方法分别用来注入Country对象、Province对象——>最后在启动类中使用注解@Import把这个配置类给导入进来——>这样就注入到Ioc容器当中了——>可是真的是自动配置了吗??

  • 之前学习springboot整合mybatis的时候,只用引入mybatis的起步依赖就行了,不用去手动的注入对应的bean对象(自动注入到Ioc容器当中),并没有写任何的配置

四、自动配置——源码分析

(1)回顾学习
  • 当程序引入 "spring-boot-starter-web" 起步依赖,启动后。会自动往Ioc容器中注入DispatcherServlet类
  • 验证是不是如上所说?
  • 首先pom文件中并没有引入web依赖(只引入了一个springboot的核心起步依赖)


  • 回到启动类。将程序启动后,将返回的Ioc容器接收一下。使用ApplicationContext context = SpringApplication.run(SpringbootAutoConfigApplication.class,args);然后用这个context对象调用方法getBean(String name),里面的name参数写上面要测试的类"dispatcherServlet"。然后把他打印输出到控制台。

  • 因为没有引入web的起步依赖,所以Ioc容器中并没有该指定类的对象。报错

  • 重新导入完web的起步依赖后(别忘了刷新一下Maven)再重新运行。发现获取成功!这就验证了只要引入web的起步依赖,它就会自动的往Ioc容器里面注入一个叫"dispatcherServlet"springboot是如何做到的??


(2)回到源码学习
  • 从启动类的@SpringBootApplication开始(这里之前学习Bean扫描时看到过)(鼠标停留在那,然后按ctrl进入到源码界面
  • 进去之后可以看到,注解@SpringBootApplication是一个组合注解,它组合了三个注解,如下:

(1)注解@ComponentScan

其中第三个注解@ComponentScan之前学习过,就是Bean扫描。(springboot默认只能扫描启动类所在的包及其子包。其它地方扫描不到。若想要扫描其它的包,可以手动的去添加注解@ComponentScan)


(2)注解@SpringBootConfiguration

(按住ctrl点进去)说明我们的启动类也是一个配置类??

(3)核心注解@EnableAutoConfiguration
  • 当看到这个@EnableXXX的时候,回想起之前学习注解@Import的时候,用更优雅的方式写进代码,使用组合注解——>@Enable+配置类名

(按住ctrl点进去)组合了两个注解


  • 重点关注@Import(导入注解)那行的注解。发现很熟悉"ImportSelector"。因为注解@Import经常导入两种类——>配置类、ImportSelector接口实现类


  • 现在再按住CTRL点击进来,再看到它实现"DeferredImportSelector"这个接口

  • 现在再按住CTRL点击进来,看这个接口它继承了"ImportSelector"这个接口。也就是说我们当前这个类"AutoConfigurationImportSelector"它是实现"ImportSelector"这个接口,那么必然会重写方法"selectImports()"

  • 例如之前案例学习的下面这种写法

  • 之前说过selectImports()方法,会被我们的springboot自动调用,从而得到它返回的全类名字符串数组,把对应的类的Bean对象注入到Ioc容器里。

  • 然后之前在selectImports()方法中,返回的全类名,我们并没有"写死",而是从配置文件中读取。在return返回回去。现在继续向下看,首先它return的是一个对象调用返回值,然后将其转换为字符串数组。现在核心就在"autoConfigurationEntry"这个对象上。

  • 因此需要猜想,这个方法getAutoConfigurationEntry()里面肯定要知道配置文件在哪里。然后现在跟踪这个方法——>返回的是一个新(new)的对象——>其中两个参数:
    "configurations"跟我们的配置相关

  • 然后又跟getCandidateConfigurations()方法有关,再继续跟进——>它调用了一个.load()方法,这是不是加载的意思。而且它后面的参数是一个类名"AutoConfiguration",后面会继续看到。往后再跟进就很复杂,先到这里继续看。
  • 其次还能往下看到底下有一段断言——>它是说:"这个configurations不能为空",如果为空了就出现下面的提示!!——>重点看下面的提示:"在这个METC-INF目录下的spring文件中有一串很长的配置文件.imports",以后将这个配置文件称为"dear imports配置文件"

  • 接着我们去寻找上面所说的配置文件。回到pom文件,当时引入了一个springboot的核心起步依赖。按住ctrl进去——>

  • 进入之后可以看到autoconfigure,顾名思义就是自动配置的意思

  • 接着来到左边查看第三方库,找到上面的autoconfigure,然后看到上面的目录METC-INF——>spring目录——>对应的"dear imports"配置文件——>打开看到之后全是一些全类名,程序会从里面读取,然后使用——>然后在配置文件中ctrl+f(搜索其中一个类名"DispatcherServletAutoConfiguration")这个类是不是很熟悉,之前引入web起步依赖,它会自动注入类"DispatcherServlet"的Bean对象进入Ioc容器——>接着我们点击进去看看——>这个类添加一个注解@AutoConfiguration,顾名思义就是自动配置的意思——>再点进去就看到它也是一个组合注解!——>其中有一个注解@Configuration,说的明白一点就是说明前面"DispatcherServletAutoConfiguration"这个类就是一个配置类,然后用上注解@AutoConfiguration就是为了完成自动配置的——>然后下面还有一个注解@ConditionalOnClass,这个是不是很熟悉(在bean注册条件里的),它在这的意思就是如果环境里面有"DispatcherServlet"这个类,这个时候这个自动配置类"DispatcherServletAutoConfiguration"起效果,将来就会自动的注入一个"DispatcherServlet"对象,如果环境里面没有,自动配置类就不生效,不注入了——>接着它里面还提供了一个内部的配置类。这个类里面提供了一个重要的方法——>方法的返回值类型是"DispatcherServlet"。方法的内部new了一个"DispatcherServlet"对象,而且这个方法添加了一个@Bean注解,而我们现在发现这个方法和之前自己的操作没什么区别!!——>就是都是声明一个方法,然后再声明一个注解@Bean——>而这个地方最核心的地方就是:它让这个类"DispatcherServletAutoConfiguration"放在指定的配置文件中,然后springboot就能够自动的读取到这个全类名,然后把这个配置类的对象注入到Ioc容器当中,而这个配置类当中还有一个配置类,而且内部的配置类中还有一些方法并添加注解@Bean,所以springboot它会自动的继续解析,直到把这些@Bean所注解的方法全部解析到,执行这些方法,把返回值注入到Ioc容器当中——>所以我们自动配置的核心就再这个配置文件当中!!!——>源码分析查看到这里吧。







(4)对刚刚源码的一个大致总结(梳理)
  • 从刚刚开始——>我们是从注解@SpringBootApplication开始的,它是一个组合注解,它组合了一个非常重要的注解@EnableAutoConfiguration,开启自动配置——>而这个@EnableAutoConfiguration也是一个组合注解,它组合了@Import注解,导入了一个"AutoConfigurationImportselector"这个类,这个类是"Importselector"的实现类,所以它里面重写了一个selectImports()方法,这个方法内部通过层层调用,会读取一个配置文件——>是一个xxx.spring.imports配置文件,在这个配置文件中,写了很多的全类名——>这些类都是自动配置类,其中有一个类"DispatcherServletAutoConfiguration",它是完成"DispatcherServlet"类Bean对象的自动注入的——>这个类"DispatcherServletAutoConfiguration"添加了两个注解,第一个是注解@AutoConfiguration,标识当前这个类是一个自动配置类。第二个是注解@Conditional0nClass,这个是标识用来设置Bean的注册条件,如果环境中有类"DispatcherServlet",那么这个自动配置类就自动生效,否则不生效——>也就是当引入了web起步依赖之后,我们的springboot就会帮忙自动的将一个类"DispatcherServlet"的bean对象注入到Ioc容器中——>而自动注入的代码核心就在底下,写了一个方法,方法的返回值类型就是类"DispatcherServlet",这个方法的返回值声明了一个注解@Bean

  • 说了这么多,自动配置的核心就是在这个".imports"配置文件当中。也就是在面试当中提到这个文件,就答案已经正确了一半了。但是在网络很多文章当中,把这个文件叫做"spring deer factories",因为在以前springboot的版本用的是其它的配置文件名。

五、解决问题

(1)前面提到的案例中是否自动配置问题??之前写的代码并没有达到自动配置的效果,因为需要手动的提供一个配置类,然后写注解@Import,这样很麻烦。如果想要自动达到配置的效果,那么这个配置类就不应该自己去提供!也就是谁提供下面的Bean对象,就提供这个配置类

  • 也就是"CommonConfig"这个配置类,要让第三方jar包提供
  • 然后还要提供应该自动配置类"CommomAutoConfig",并且在这个自动配置类上添加两个注解。分别是@AutoConfiguration它用来标识这个类是一个自动配置类、通过@Import注解把这个配置类"CommonConfig"导入进来,然后需要提供一个配置文件".imports",在这个配置文件中,把这个"CommomAutoConfig"自动配置类的全类名给它写入,具体图片操作如下展示:

  • 开始演示如何实现自动配置操作
  • 首先安装好对应的jar包,里面的代码已经基本写好

  • 接着安装到Maven的本地仓库
  • 接着在pom文件中手动的添加对应的依赖(common-pojo)完毕之后记得刷新Maven

  • 然后去查看对应库里安装的jar包(2.0版本的)

  • 继续查看里面的内容(配置类、自动配置类)
  • 自动配置类里用到两个注解@AutoConfiguration(标识当前是自动配置类)、@Import(把我们的"CommonConfig"这个配置类导入进来,也就是当springboot读取到这个自动配置类的时候,它就会读取到注解@Import,从而间接的读取到"CommonConfig"这个配置类)


  • 仿照之前在源码看到的——>在对应的目录下提供了一个配置文件"xxx.imports"

  • 在".imports"文件当中写了自动配置类的对应的全类名

  • 回到启动类,是否能够测试成功??打印getBean("province"),看是是否"Province"类的Bean对象已经能够自动的注入成功了。成功了!

  • 发现运行程序,输出成功!就证明我们已经达到自动配置的效果了!!实在看不懂区别可以查看我昨天写的博客文章。这个地方确实难理解,本人也同样!!!SpringBoot学习(8)(Bean注册条件)(@Conditional的衍生注解)-CSDN博客文章浏览阅读627次,点赞8次,收藏6次。主要是关于springboot中Bean对象的注册条件的合理使用时机、方法。其中演示了如何注册条件将第三方jar包中的对应实体类的Bean对象注入到loc容器当中。注解包括@Bean,@Conditional及其衍生注解@ConditionalOnProperty、@Conditional0nMissingBean、@ConditionalOnclass。https://blog.csdn.net/m0_74363339/article/details/141958063?spm=1001.2014.3001.5501

  • 现在可以把启动类的@Import去掉了,因为能够自动配置了

六、分析总结

(1)小总结
  • 通过源码分析,可以看到springboot自动配置无非就是提供一个自动配置类,然后把这个类名写到指定的配置文件里边。
(2)面试(总结)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2113761.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文件系统 文件描述符fd 重定向原理 缓冲区

文章目录 基础的文件操作文件的系统调用接口位图向文件中写入标记位选项总结&#xff1a;open的返回值文件描述符fdfd012与硬件的关系read && stat 重定向dup2 缓冲区的理解经典的例子 基础的文件操作 引子&#xff1a; #include <stdio.h>int main() {FILE* f…

[Linux]:环境变量与进程地址空间

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 1. 环境变量 1.1 概念 **环境变量(environment variables)**一般是指在操作…

在Unity环境中使用UTF-8编码

为什么要讨论这个问题 为了避免乱码和更好的跨平台 我刚开始开发时是使用VS开发,Unity自身默认使用UTF-8 without BOM格式,但是在Unity中创建一个脚本,使用VS打开,VS自身默认使用GB2312(它应该是对应了你电脑的window版本默认选取了国标编码,或者是因为一些其他的原因)读取脚本…

自己部门日均1000+告警?如何减少90%无效告警?

目录标题 一、告警的类别1.技术告警1.1基础设施告警1.2基本服务告警 2.业务告警3.监控大盘告警 二、为何需要告警治理&#xff1f;三、治理迫在眉睫1.1告警治理策略1.2核心监控告警点1.3避免告警反模式1.4告警规约制定1.5自动化处理 一、告警的类别 一般的告警分为以下几点&am…

ISP面试准备2

系列文章目录 文章目录 系列文章目录前言一.如何评价图像质量&#xff1f;二.引起图像噪声的原因三. ISP3.1 ISP Pipeline主要模块3.1.1坏点校正&#xff08;Defect Pixel Correction, DPC&#xff09;3.1.2黑电平校正&#xff08;Black Level Correction, BLC&#xff09;3.1.…

面试官:synchronized的锁升级过程是怎样的?

大家好&#xff0c;我是大明哥&#xff0c;一个专注「死磕 Java」系列创作的硬核程序员。 回答 在 JDK 1.6之前&#xff0c;synchronized 是一个重量级、效率比较低下的锁&#xff0c;但是在JDK 1.6后&#xff0c;JVM 为了提高锁的获取与释放效&#xff0c;,对 synchronized 进…

基于JSP的实验室管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 Spring Boot框架 工具&#xff1a;IDEA/Eclipse、Navicat、Tomcat 系统展示 首页 用户个…

自然语言处理系列六十二》神经网络算法》MLP多层感知机算法

注&#xff1a;此文章内容均节选自充电了么创始人&#xff0c;CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》&#xff08;人工智能科学与技术丛书&#xff09;【陈敬雷编著】【清华大学出版社】 文章目录 自然语言处理系列六十二神经网络算法》MLP多层感知机算法CNN卷积…

【Python篇】PyQt5 超详细教程——由入门到精通(序篇)

文章目录 PyQt5 超详细入门级教程前言序篇&#xff1a;1-3部分&#xff1a;PyQt5基础与常用控件第1部分&#xff1a;初识 PyQt5 和安装1.1 什么是 PyQt5&#xff1f;1.2 在 PyCharm 中安装 PyQt51.3 在 PyCharm 中编写第一个 PyQt5 应用程序1.4 代码详细解释1.5 在 PyCharm 中运…

电子电气架构---私有总线通信和诊断规则

电子电气架构—私有总线通信和诊断规则 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自…

最新版 | SpringBoot3如何自定义starter(面试常考)

文章目录 一、自定义starter介绍二、自定义Starter的好处及优势三、自定义starter应用场景四、自定义starter1、创建autoconfigure的maven工程2、创建starter的maven工程3、在autoconfigure的pom文件中引入MyBatis的所需依赖4、编写自动配置类MyBatisAutoConfiguration5、编写i…

红旗EQM换电连接器哪家生产

红旗EQM换电连接器概述 红旗EQM换电连接器是针对红旗品牌电动汽车设计的一种快速更换电池的装置。它允许用户在短时间内完成电池的更换&#xff0c;从而提高电动车的使用效率和便捷性。接下来&#xff0c;我们将详细探讨红旗EQM换电连接器的相关操作步骤、所需工具以及最新的相…

[Git使用] 实战技巧

文章目录 1. 理解分叉点2. Rebase3. FixUp4. Revert1. 理解分叉点 合并分支的时候会产生分叉点 比如: 仓库有dev和feature两个分支; 操作1:dev远程新建一个文件操作2:feature提交第一次操作3:远程执行把feture合并到dev分支在可视化界面可以看到 远程Dev分支的可视化: …

MySQL 锁分类有哪些?一文带你详解!!

MySQL 锁 全局锁全局锁的应用场景全局锁的缺点 表级锁表锁元数据&#xff08;MDL&#xff09;锁MDL 锁的问题 意向锁AUTO-INC 锁 行级锁记录锁&#xff08;Record Lock&#xff09;间隙锁&#xff08;Gap Lock&#xff09;临键锁&#xff08;Next-Key Lock&#xff09;插入意向…

安卓开发板_联发科MTK开发评估套件串口调试

串口调试 如果正在进行lk(little kernel ) 或内核开发&#xff0c;USB 串口适配器&#xff08; USB 转串口 TTL 适配器的简称&#xff09;对于检查系统启动日志非常有用&#xff0c;特别是在没有图形桌面显示的情况下。 1.选购适配器 常用的许多 USB 转串口的适配器&#xf…

宝塔部署Vue项目解决跨域问题

一、前言 使用宝塔面板部署前端后端项目相比用命令行进行部署要简单许多&#xff0c;宝塔的可视化操作对那些对Linux不熟悉的人很友好。使用宝塔部署SpringBoot后端项目和Vue前端项目的方法如下&#xff1a; 1、视频教程 2、文字教程1 3、文字教程2 以上的教程完全可以按照步骤…

以太网交换机工作原理学习笔记

在网络中传输数据时需要遵循一些标准&#xff0c;以太网协议定义了数据帧在以太网上的传输标准&#xff0c;了解以太网协议是充分理解数据链路层通信的基础。以太网交换机是实现数据链路层通信的主要设备&#xff0c;了解以太网交换机的工作原理也是十分必要的。 1、以太网协议…

SQLException: No Suitable Driver Found - 完美解决方法详解

&#x1f6a8; SQLException: No Suitable Driver Found - 完美解决方法详解 &#x1f6a8; **&#x1f6a8; SQLException: No Suitable Driver Found - 完美解决方法详解 &#x1f6a8;****摘要 &#x1f4dd;****引言 &#x1f3af;****正文 &#x1f4da;****1. 问题概述 ❗…

网络层 VII(IP多播、移动IP)【★★★★★★】

一、IP 多播 1. 多播的概念 多播是让源主机一次发送的单个分组可以抵达用一个组地址标识的若干目的主机&#xff0c;即一对多的通信。在互联网上进行的多播&#xff0c;称为 IP 多播&#xff08;multicast , 以前曾译为组播&#xff09;。 与单播相比&#xff0c;在一对多的…

【go】内存分配模型

内存是怎么分配给对象的&#xff1f; 内存分配优化的地方是&#xff1f; 讲讲golang内存分配模型&#xff1f; ans: 1.按照对象的大小分配&#xff1a;先算出对象的大小如果是tiny对象&#xff0c;就从tiny block中获取地址和偏移量&#xff0c;将对象打包到mcache;如果是16B以…