【JavaEE】Spring Boot 自动装配原理(源码分析)

一. 前言

  • 我们在写Spring Boot的程序代码的时候, 可以注入很多我们没有定义过的Bean.
  • 例如:
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    public DataSourceTransactionManager transactionManager;
    @Autowired
    public AutowireCapableBeanFactory autowireCapableBeanFactory;
  • 这些对象是什么时候注入进去的, Spring 是如何做的,我们可以通过阅读源码来解决这个问题.

二.Spring Boot自动装配的原理分析.

2.1 源码阅读

  • 要搞清楚自动装配的原因, 我们需要去分析Spring Boot的启动类.

  • @SpringBootApplication 标注的类 就是SpringBoot项目的启动类, 这个注解也是SpringBoot实现自动配置的核心
    在这里插入图片描述

  • 元注解:

    • JDK中提供了4个标准的用来对注解类型进行注解的注解类, 我们称之为 meta-annotation(元注
      解)
    • @Target 描述注解的使用范围(即被修饰的注解可以用在什么地方).
    • @Retention 描述注解保留的时间范围.
    • @Documented 描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息
    • @Inherited 使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,则
      其子类将自动具有该注解
      )
  • @SpringBootConfiguration 在这里插入图片描述

里面就是@Configuration, 标注当前类为配置类, 其实只是做了一层封装改了个名字而已.
(@Indexed注解,是用来加速应用启动的, 不用关心), 本质上就是将启动类交给Spring进行管理

  • @ComponentScan (包扫描)
    可以通过 basePackageClasses 或 basePackages 来定义要扫描的特定包, 如果没有定义
    特定的包, 将从声明该注解的类的包开始扫描, 这也是为什么SpringBoot项目声明的注解类必须要在启动类的目录下,这样通过@Controller , @Service , @Repository , @Component , @Configuration ,@Bean标注的类/对象,就会被Spring进行管理. excludeFilters 自定义过滤器, 通常用于排除一些类, 注解等

2.2 @EnableAutoConfiguration(自动装配的核心注解)

  • 观察@EnableAutoConfiguration注解的实现:
    在这里插入图片描述
    这个注解包含两部分:

2.2.1@AutoConfigurationPackage

源码如下:
在这里插入图片描述
这个注解主要是导入一个配置文件 AutoConfigurationPackages.Registrar.class
在这里插入图片描述

  • registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry): 这个方法是ImportBeanDefinitionRegistrar接口的一部分,用于在Spring应用程序上下文中注册额外的bean定义。当一个@Configuration类使用了@Import注解并且指定了实现ImportBeanDefinitionRegistrar接口的类时,这个方法会被调用。在这个例子中,它使用PackageImports(一个假定存在的辅助类)来获取包名,并将这些包名作为字符串数组传递给另一个重载的register方法,以便在注册表中注册这些包中的类作为Spring bean定义。

  • determineImports(AnnotationMetadata metadata): 这个方法是DeterminableImports接口的一部分,用于确定哪些类应该被导入到当前的@Configuration类或@SpringBootApplication类中。在这个例子中,它返回了一个单例集合(Set),其中包含了一个PackageImports对象。这个对象封装了应该被扫描的包的信息,这样Spring就能自动发现并注册这些包中的@Component、@Service、@Repository等注解的类。

Registrar实现了 ImportBeanDefinitionRegistrar 类, 就可以被注解@Import导⼊到spring
容器里. (String[])(new PackageImports(metadata)).getPackageNames().toArray(new
String[0]) : 当前启动类所在的包名. 所以:@AutoConfigurationPackage 就是将启动类所在的包下⾯所有的组件都扫描注冊到spring 容器中.

2.2.2 @Import({AutoConfigurationImportSelector.class})

  • 使用@Import注解,导入了实现ImportSelector接口的实现类.
    在这里插入图片描述

  • selectImports() 方法底层调用 getAutoConfigurationEntry() 方法, 获取可自动配置的配置类信息集合.
    在这里插入图片描述

  • getAutoConfigurationEntry() 方法通过调用getCandidateConfigurations(annotationMetadata, attributes) 方法获取在配置文件中配置的所有自动配置类的集合
    在这里插入图片描述

  • getCandidateConfigurations 方法的功能:

    • 获取所有基METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imp
      orts 文件, META-INF/spring.factories 文件中配置类的集合. 在引入的起步依赖中, 通常都有包含以上两个文件
      在这里插入图片描述

这里面包含了很多第三方依赖的配置文件(连续按两下shift可以查看对应的源码)

  1. 在加载自动配置类的时候, 并不是将所有的配置全部加载进来, 而是通过@Conditional等注解的判
    断进行动态加载.@Conditional是spring底层注解, 意思就是根据不同的条件, 来进行自己不同的条件判断,如果满足指定的条件,那么配置类里边的配置才会生效.
  2. META-INF/spring.factories文件是Spring内部提供的一个约定俗成的加载方式, 只需要在模块的
    META-INF/spring.factories文件中配置即可, Spring就会把相应的实现类注入到Spring容器中.
    注: 会加载所有jar包下的classpath路径下的META-INF/spring.factories文件, 这样文件不止一个
  • 比如 Redis的配置: RedisAutoConfiguration
    在这里插入图片描述
    由于我这个项目的pom依赖中,没有加入redis相关的依赖, 所以会根据注解@ConditionalOnMissingBean不进行加载

三.总结.

  • SpringBoot 自动配置原理的大概流程如下:
    在这里插入图片描述
    当SpringBoot程序启动时, 会加载配置文件当中所定义的配置类, 通过 @Import 注解将这些配置类全
    部加载到Spring的IOC容器中, 交给IOC容器管理

  • SpringBoot的自动配置原理源码口是 @SpringBootApplication 注解, 这个注解封装了3个注

    • @SpringBootConfiguration 标志当前类为配置类
    • @ComponentScan 进行包扫描(默认扫描的是启动类所在的当前包及其子包)
    • @EnableAutoConfiguration
      • @Import 注解 : 读取当前项目下所有依赖jar包中 META-INF/spring.factories ,
        METAINF/spring/org.springframework.boot.autoconfigure.AutoConfigurat
        ion.imports 两个文件里面定义的配置类(配置类中定义了 @Bean 注解标识的方法)
      • @AutoConfigurationPackage : 把启动类所在的包下面所有的组件都注入到 Spring
        容器中

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

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

相关文章

UnrealEngine摸索(一)——Static Mesh Actor不会阻挡可见性查询解决方法

实际开发中遇到题目所述的问题,对解决方法进行记录 文章目录 问题描述解决方案 问题描述 博主在开发FPS游戏过程中,使用 LineTraceSingleByChannel 进行可视性检测,即其参数 Channel Visiblity,对于命中的第一个物体应用相应的处…

Web开发:VUE3小白开发入门基础笔记

一、基本语法 1.click 后端路由&#xff1a;api/GetDataList 返回值&#xff1a;Value 前端要做的事&#xff1a; ①拿到Value值&#xff0c;传到a标签 ②a标签有一个按钮&#xff0c;每点击一下&#xff0c;Value的值加一。 前端需要用click语法 【代码】 <template>…

《0基础》学习Python——第十八讲__爬虫/<1>

一、什么是爬虫 爬虫是一种网络数据抓取的技术。通过编写程序&#xff08;通常使用Python&#xff09;&#xff0c;爬虫可以自动化地访问网页&#xff0c;解析网页内容并提取出所需的数据。爬虫可以用于各种用途&#xff0c;如搜索引擎的索引&#xff0c;数据分析和挖掘&#x…

Vue 3项目安装Element-Plus

Element Plus 是一个基于 Vue 3 的现代前端UI框架&#xff0c;它旨在提升开发体验&#xff0c;并为开发者提供高效、优雅的组件。如果你正在使用 Vue 3 进行项目开发&#xff0c;那么安装和集成 Element Plus 是一个不错的选择。在本文中&#xff0c;博主将详细介绍如何在 Vue …

[嵌入式Linux]-常见编译框架与软件包组成

嵌入式常见编译框架与软件包组成 1.嵌入式开发准备工作 主芯片资料包括&#xff1a; 主芯片资料 主芯片开发参考手册&#xff1b;主芯片数据手册&#xff1b;主芯片规格书&#xff1b; 硬件参考 主芯片硬件设计参考资料&#xff1b;主芯片配套公板硬件工程&#xff1b; 软件…

OD C卷 - 数据单元的变量替换

数据单元的变量替换&#xff08;100&#xff09; 输入描述&#xff1a; 输入一行数据&#xff0c;用逗号分割每个单元格&#xff0c;尾部没有逗号&#xff0c;最多26个单元格&#xff0c;对应编号A-Z&#xff1b;每个单元格内容&#xff1a;字母、数字、<> 单元格引用&…

linux 公平调度关键点记录

1.如何计算进程的物理运行时间和虚拟运行时间 调度周期(sched period)nice valuerealruntime(实际运行时间)vruntime(虚拟运行时间)10ms05ms5ms05ms5ms10ms-209.996ms0.1153ms150.004ms0.11378ms可以看到对于-20和15两个进程的情况下,其虚拟运行时间是基本相同的,这正式cf…

今天我们聊聊C#的并发和并行

并发和并行是现代编程中的两个重要概念&#xff0c;它们可以帮助开发人员创建高效、响应迅速、高性能的应用程序。在C#中&#xff0c;这些概念尤为重要&#xff0c;因为该语言提供了对多线程和异步编程的强大支持。本文将介绍C#中并发和并行编程的关键概念、优点&#xff0c;并…

如何使用录屏软件录制声音?超实用的4个电脑录屏方法!

在现代的数字时代&#xff0c;录屏软件已经成为我们日常工作和学习中不可或缺的工具之一。无论是制作教学视频、演示软件功能&#xff0c;还是记录游戏过程&#xff0c;录屏软件都能提供极大的帮助。但许多人在使用录屏软件时&#xff0c;可能会遇到一个问题&#xff1a;如何将…

Godot游戏制作 03世界构建1.0版

在game场景&#xff0c;删除StaticBody2D节点&#xff0c;添加TileMap节点 添加TileSet图块集 添加TileSet源 拖动图片到图块&#xff0c;自动创建图块 使用橡皮擦擦除。取消橡皮擦后按住Shift创建大型图块。 进入选择模式&#xff0c;TileMap选择绘制&#xff0c;选中图块后在…

Leetcode 721.账户合并(hash+dfs)☆

思路&#xff1a; 最核心的地方在于如何合并&#xff1f;这里是通过具有相同的email进行账户的合并&#xff0c;这个相同的email类似于图中的共同节点将两个账户连接起来&#xff0c;所以将原来 账户名 -> 邮件1 邮件2.。。变成hash 邮件1 ->账户id1&#xff0c;账户id2…

Meta革命性发布:Llama 3.1——性能最强的AI开源模型,开启智能新时代!

前言 &#x1f680; Meta隆重推出Llama 3.1&#xff1a;迄今为止性能最强的AI模型 Meta公司近日发布了他们最新的AI语言模型——Llama 3.1&#xff0c;这一消息迅速在科技界掀起了波澜。作为猫头虎技术团队&#xff0c;我们将为大家详细解析Llama 3.1的强大功能及其应用前景。…

Android APP 音视频(02)MediaProjection录屏与MediaCodec编码

说明&#xff1a; 此MediaProjection 录屏和编码实操主要针对Android12.0系统。通过MediaProjection获取屏幕数据&#xff0c;将数据通过mediacodec编码输出H264码流&#xff08;使用ffmpeg播放&#xff09;&#xff0c;存储到sd卡上。 1 MediaProjection录屏与编码简介 这里…

HTML5 + CSS3

HTML 基础 准备开发环境 1.vscode 使用 新建文件夹 ---> 左键拖入 vscode 中 2.安装插件 扩展 → 搜索插件 → 安装打开网页插件&#xff1a;open in browser汉化菜单插件&#xff1a;Chinese 3.缩放代码字号 放大,缩小&#xff1a;Ctrl 加号&#xff0c;减号 4.设…

机械设计基础B(学习笔记)

绪论 机构&#xff1a;是一些具备各自特点的和具有确定的相对运动的基本组合的统称。 组成机构的各个相对运动部分称为构件。构件作为运动单元&#xff0c;它可以是单一的整体&#xff0c;也可以是由几个最基本的事物&#xff08;通常称为零件&#xff09;组成的刚性结构。 构件…

机器学习笔记1——监督学习和无监督学习

一、机器学习的定义 1.机器学习的定义&#xff1a;计算机程序从经验E中学习&#xff0c;解决某一任务T进行某一性能度量P&#xff0c;通过P测定在T上的表现因经验E而提高。 2.在各种不同类型的学习算法中&#xff0c;主要分为监督学习和无监督学习。 监督学习&#xff1a;就是我…

面试题---Mybatis

Mybatis MyBatis中${}取值和#{}取值的区别 {}能够防止SQL注入&#xff0c;因为底层使用PreparedStatement对象&#xff0c;预编译&#xff0c;性能较高 ${}不能防止SQL注入&#xff0c;因为底层使用Statement对象&#xff0c;不会预编译而是拼接字符串&#xff0c;性能较低 …

华杉研发九学习日记17 正则表达式 异常

华杉研发九学习日记17 一&#xff0c;正则表达式 ^ $ 作用&#xff1a; 测试字符串内的模式(匹配) 例如&#xff0c;可以测试输入字符串&#xff0c;以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证. 替换文本&#xff08;替换》 可以使用正则表达式来…

vue3 学习笔记17 -- 基于el-menu封装菜单

vue3 学习笔记17 – 基于el-menu封装菜单 前提条件&#xff1a;组件创建完成 配置路由 // src/router/index.ts import { createRouter, createWebHashHistory } from vue-router import type { RouteRecordRaw } from vue-router export const Layout () > import(/lay…

PyTorch 2.0 GPU Nvidia运行库的安装

【图书推荐】《PyTorch深度学习与计算机视觉实践》-CSDN博客 假设读者电脑带有NVIDIA 20 以上系列的显卡。 我们以CUDA 11.7cuDNN 8.2.0&#xff08;其他更高版本的组合&#xff0c;读者可以执行查阅PyTorch官网获得&#xff09;为例&#xff0c;讲解PyTorch 2.0 GPU版本的安…