SpringBoot自动装配详解

SpringBoot自动装配

在讲之前先了解一下,手动装配的流程。

在没有Spring Boot的情况下,你需要手动配置和添加相关依赖,以实现类似于Spring Boot自动装配的功能。主要步骤:

  1. 引入Spring相关依赖: 首先,你需要引入Spring框架的相关依赖,包括核心容器(spring-context)、AOP(spring-aop)、数据访问(spring-jdbc、spring-orm)、事务管理(spring-tx)、Web(spring-web)等,具体依赖根据项目需求而定。

    <!-- Spring Core Container -->
    <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.10.RELEASE</version> <!-- 请替换为最新版本 -->
    </dependency><!-- Spring AOP -->
    <dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.10.RELEASE</version>
    </dependency><!-- 其他Spring相关依赖... -->
    
  2. 手动配置Spring配置文件: 在没有Spring Boot的情况下,你需要手动创建Spring的配置文件(例如XML配置文件)来定义和配置Spring容器中的Bean、数据源、事务管理等。

    <!-- applicationContext.xml -->
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 配置数据源、事务管理、其他Bean... --></beans>
    
  3. 手动扫描组件和配置类: Spring Boot自动扫描组件的特性在没有Spring Boot的情况下需要手动配置。你可以通过在配置文件中添加 <context:component-scan> 元素来启用组件扫描。

    <!-- applicationContext.xml -->
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"xmlns:context="http://www.springframework.org/schema/context"><context:component-scan base-package="com.example" /></beans>
    
  4. 手动配置Web应用(如果有): 如果你的项目是一个Web应用,你需要手动配置Servlet、Filter、Listener等。

    <!-- web.xml -->
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><!-- 配置Servlet、Filter、Listener等... --></web-app>
    

而在SpringBoot中,你不需要写这一大堆的xml配置文件,很多配置只需要通过Spring Boot 的全局配置文件 application.propertiesapplication.yml进行修改,比如更换端口号,配置 JPA 属性等等。

优点👌:因为Spring Boot提供了自动装配、默认配置和内嵌服务器等功能,让你更专注于业务逻辑的开发而不用过多关心底层配置

进入正题
什么是SpringBoot自动装配?

Spring Boot 的自动装配(Auto-Configuration)原理是基于Spring Framework的条件化配置和@EnableAutoConfiguration注解实现的。这种机制允许开发者在项目中引入相关的依赖,Spring Boot 将根据这些依赖自动配置应用程序的上下文和功能。

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。

例如在SpringBoot项目中,引入Redis,只需要在Maven中,引入一个Redis的starter

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

然后在配置文件中写下Redis的配置就可以调用Redis的服务,这就是SpringBoot的强大之处

在这里插入图片描述

在这里插入图片描述

通俗来讲,自动装配就是通过注解或一些简单的配置就可以在SpringBoot的帮助下开启和配置各种功能,比如数据库访问、Web开发

SpringBoot自动装配原理

首先点进@SpringBootApplication注解的内部

在这里插入图片描述

让我们逐个解释这些注解的作用:

  1. @Target({ElementType.TYPE}): 该注解指定了这个注解可以用来标记在类上。在这个特定的例子中,这表示该注解用于标记配置类。
  2. @Retention(RetentionPolicy.RUNTIME): 这个注解指定了注解的生命周期,即在运行时保留。这是因为 Spring Boot 在运行时扫描类路径上的注解来实现自动配置,所以这里使用了 RUNTIME 保留策略。
  3. @Documented: 该注解表示这个注解应该被包含在 Java 文档中。它是用于生成文档的标记,使开发者能够看到这个注解的相关信息。
  4. @Inherited: 这个注解指示一个被标注的类型是被继承的。在这个例子中,它表明这个注解可以被继承,如果一个类继承了带有这个注解的类,它也会继承这个注解。
  5. @SpringBootConfiguration: 这个注解表明这是一个 Spring Boot 配置类。如果点进这个注解内部会发现与标准的 @Configuration 没啥区别,只是为了表明这是一个专门用于 Spring Boot 的配置。
  6. @EnableAutoConfiguration: 这个注解是 Spring Boot 自动装配的核心。它告诉 Spring Boot 启用自动配置机制,根据项目的依赖和配置自动配置应用程序的上下文。通过这个注解,Spring Boot 将尝试根据类路径上的依赖自动配置应用程序。
  7. @ComponentScan: 这个注解用于配置组件扫描的规则。在这里,它告诉 Spring Boot 在指定的包及其子包中查找组件,这些组件包括被注解的类、@Component 注解的类等。其中的 excludeFilters 参数用于指定排除哪些组件,这里使用了两个自定义的过滤器,分别是 TypeExcludeFilterAutoConfigurationExcludeFilter

看下来,其实@SpringBootApplication可以看作是@Configuration、@EnableAutoConfiguration、@ComponentScan的组合

@EnableAutoConfiguration

这个注解是实现自动装配的核心注解

  1. @AutoConfigurationPackage,将项目src中main包下的所有组件注册到容器中,例如标注了Component注解的类等等

  2. @Import({AutoConfigurationImportSelector.class}),是自动装配的核心,👇就来分析一下它

AutoConfigurationImportSelector

AutoConfigurationImportSelector 是 Spring Boot 中一个重要的类,它实现了 ImportSelector 接口,用于实现自动配置的选择和导入。具体来说,它通过分析项目的类路径和条件来决定应该导入哪些自动配置类。

代码太多,选取部分主要功能的代码

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {// ... (其他方法和属性)// 获取所有符合条件的类的全限定类名,例如RedisTemplate的全限定类名(org.springframework.data.redis.core.RedisTemplate;),这些类需要被加载到 IoC 容器中。@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {// 扫描类路径上的 META-INF/spring.factories 文件,获取所有实现了 AutoConfiguration 接口的自动配置类List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 过滤掉不满足条件的自动配置类,比如一些自动装配类configurations = filter(configurations, annotationMetadata, attributes);// 排序自动配置类,根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序sort(configurations, annotationMetadata, attributes);// 将满足条件的自动配置类的类名数组返回,这些类将被导入到应用程序上下文中return StringUtils.toStringArray(configurations);}// ... (其他方法)protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 获取自动配置类的候选列表,从 META-INF/spring.factories 文件中读取// 通过类加载器加载所有候选类List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());// 过滤出实现了 AutoConfiguration 接口的自动配置类configurations = configurations.stream().filter(this::isEnabled).collect(Collectors.toList());// 对于 Spring Boot 1.x 版本,还需要添加 spring-boot-autoconfigure 包中的自动配置类// configurations.addAll(getAutoConfigEntry(getAutoConfigurationEntry(metadata)));return configurations;}// ... (其他方法)protected List<String> filter(List<String> configurations, AnnotationMetadata metadata,AnnotationAttributes attributes) {// 使用条件判断机制,过滤掉不满足条件的自动配置类configurations = configurations.stream().filter(configuration -> isConfigurationCandidate(configuration, metadata, attributes)).collect(Collectors.toList());return configurations;}// ... (其他方法)protected void sort(List<String> configurations, AnnotationMetadata metadata,AnnotationAttributes attributes) {// 根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序对自动配置类进行排序configurations.sort((o1, o2) -> {int i1 = getAutoConfigurationOrder(o1, metadata, attributes);int i2 = getAutoConfigurationOrder(o2, metadata, attributes);return Integer.compare(i1, i2);});}// ... (其他方法)}

梳理一下😂,以下是 AutoConfigurationImportSelector 的主要工作:

  1. 扫描类路径: 在应用程序启动时,AutoConfigurationImportSelector 会扫描类路径上的 META-INF/spring.factories 文件,这个文件中包含了各种 Spring 配置和扩展的定义。在这里,它会查找所有实现了 AutoConfiguration 接口的类,具体的实现为getCandidateConfigurations方法。
  2. 条件判断: 对于每一个发现的自动配置类,AutoConfigurationImportSelector 会使用条件判断机制(通常是通过 @ConditionalOnXxx 注解)来确定是否满足导入条件。这些条件可以是配置属性、类是否存在、Bean是否存在等等。

​ 例如:下面这个配置类,只有在RabbitTemplate.class, Channel.class存在才会去加载

@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}

有兴趣的童鞋可以详细了解下 Spring Boot 提供的条件注解

  • @ConditionalOnBean:当容器里有指定 Bean 的条件下
  • @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
  • @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
  • @ConditionalOnClass:当类路径下有指定类的条件下
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下
  • @ConditionalOnProperty:指定的属性是否有指定的值
  • @ConditionalOnResource:类路径是否有指定的值
  • @ConditionalOnExpression:基于 SpEL 表达式作为判断条件
  • @ConditionalOnJava:基于 Java 版本作为判断条件
  • @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
  • @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
  • @ConditionalOnWebApplication:当前项目是 Web 项 目的条件下
  1. 根据条件导入自动配置类: 满足条件的自动配置类将被导入到应用程序的上下文中。这意味着它们会被实例化并应用于应用程序的配置。

懂了上面这些,我们其实可以自己实现一个Starter,非常简单

自定义Starter

第一步,创建threadpool-spring-boot-starter工程

img

第二步,引入 Spring Boot 相关依赖

img

第三步,创建ThreadPoolAutoConfiguration

img

第四步,在threadpool-spring-boot-starter工程的 resources 包下创建META-INF/spring.factories文件

img

最后新建工程引入threadpool-spring-boot-starter

img

测试通过!!!

img

总结

Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖

希望这篇文章能够帮助你更好地理解SpringBoot自动装配,Happy coding! 🚀;点个关注,关注更多干货😘

参考链接:https://javaguide.cn/system-design/framework/spring/spring-boot-auto-assembly-principles.html

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

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

相关文章

基于springboot+vue实现食品安全管理系统项目【项目源码+论文说明】

基于springboot实现食品安全管理系统演示 摘要 食品行业同其他行业有很多的差别&#xff0c;食品行业不仅要管食品的生产和销售&#xff0c;还要管食品的库存和保质期&#xff0c;那么对于食品管理者来说&#xff0c;就存在着一定的难度。况且食品的种类复杂&#xff0c;存储条…

Redis分段锁,如何设计?

问题场景&#xff1a;热点库存扣减问题 秒杀场景&#xff0c;有一个难度的问题&#xff1a;热点库存扣减问题。 既要保证不发生超卖 又要保证高并发 如果解决这个高难度的问题呢&#xff1f; 答案就是使用redis 分段锁。 什么是分布式锁&#xff1f; 一个分布式系统中&am…

关于OpenAI最新的成果Sora的思考

目录 前言: 1.Sora的技术特点 1.1技术架构 1.2算法原理&#xff1a; 1.2.1自然语言处理&#xff08;NLP&#xff09;&#xff1a; 1.2.2深度学习&#xff1a; 1.2.3视频生成与编码&#xff1a; 1.3实现过程&#xff1a; 1.3.1NLP&#xff08;自然语言处理&#xff09;模…

手写分布式配置中心(三)增加实时刷新功能(短轮询)

要实现配置自动实时刷新&#xff0c;需要改造之前的代码。代码在https://gitee.com/summer-cat001/config-center​​​​​​​ 服务端改造 服务端增加一个版本号version&#xff0c;新增配置的时候为1&#xff0c;每次更新配置就加1。 Overridepublic long insertConfigDO(…

Vue3 中的代理原理详解

Vue3 中的代理原理详解 Vue3 中引入了代理&#xff08;Proxy&#xff09;机制&#xff0c;取代了 Vue2 中的 Object.defineProperty() 机制&#xff0c;用于实现数据响应式。代理机制是 ES6 中新增的特性&#xff0c;它可以用来自定义对象中的操作&#xff0c;比如属性查找、赋…

【代码随想录python笔记整理】第十七课 · 判断集合成员

前言:本笔记仅仅只是对内容的整理和自行消化&#xff0c;并不是完整内容&#xff0c;如有侵权&#xff0c;联系立删。 一、集合 在之前提到&#xff0c;哈希表主要是用来判断给定的整数是否存在于给定的数据中。而在上一节中我们使用了数组&#xff0c;通过索引来实现哈希表的功…

备战蓝桥(模板篇)

扩展欧德里几算法 质数筛 分解质因数 LCA BFS floyd Dijkstra prime 日期是否合法 Tire异或 模拟散列表 字符哈希 Tire字符串统计

【C++】学习记录

一、第一个C程序 #include<iostream> using namespace std;int main() {cout << "Hello World!";return 0; } 二、数据类型、变量与常量、运算符 2.1 数据类型 2.2 变量与常量 2.3 运算符 三 、判断语句&#xff08;if-else、switch-case&#xff09; …

从0到1入门C++编程——10 stack容器、queue容器、list容器、set容器、map容器

文章目录 一、stack容器二、queue容器三、list容器1、构造函数2、赋值和交换3、大小及判空4、插入和删除5、数据存取6、反转和排序7、排序案例 四、set/multiset容器1、构造和赋值2、大小和交换3、插入和删除4、查找和统计5、set和multiset的区别6、pair对组的创建7、排序及规则…

边缘计算基础知识

目录 边缘计算简介任务卸载简介边缘存储系统 边缘计算简介 边缘计算是指利用靠近数据生成的网络边缘侧的设备&#xff08;如移动设备、基站、边缘服务器、边缘云等&#xff09;的计算能力和存储能力&#xff0c;使得数据和任务能够就近得到处理和执行。 一个典型的边缘计算系…

泽众云真机-为什么老机型专区大部分是维护中?如何解决

最近&#xff0c;泽众云真机平台有几位用户向我们咨询&#xff0c;为什么老机型专区大部分是维护中&#xff1f;我想使用这些机型怎么办&#xff1f; 首先来解释一下&#xff0c;为什么叫“老机型专区”&#xff1f;因为一些老的机型之前一直是在线状态&#xff0c;通过我们长期…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Checkbox)

提供多选框组件&#xff0c;通常用于某选项的打开或关闭。 说明&#xff1a; API version 11开始&#xff0c;Checkbox默认样式由圆角方形变为圆形。 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口…

Hello C++ (c++是什么/c++怎么学/c++推荐书籍)

引言 其实C基础语法基本上已经学完&#xff0c;早就想开始写C的博客了&#xff0c;却因为其他各种事情一直没开始。原计划是想讲Linux系统虚拟机安装的&#xff0c;后来考虑了一下还是算了&#xff0c;等Linux学到一定程度再开始相关博客的写作和发表吧。今天写博客想给C开个头…

解决:ModuleNotFoundError: No module named ‘paddle‘

错误显示&#xff1a; 原因&#xff1a; 环境中没有‘paddle’的python模块&#xff0c;但是您在尝试导入 解决方法&#xff1a; 1.普通方式安装&#xff1a; pip install paddlepaddle #安装命令 2.镜像源安装 pip install paddlepaddle -i https://pypi.tuna.tsinghua.e…

饮料换购 刷题笔记

直接开个计数器mask 每当饮料现存数-1&#xff1b; cnt;且mask; 一旦mask达到3 饮料现存数 计数器清零3 代码 #include <iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int main(){ int n; …

【论文整理】自动驾驶场景中Collaborative Methods多智能体协同感知文章创新点整理

Collaborative Methods F-CooperV2VNetWhen2commDiscoNetAttFusionV2X-ViTCRCNetCoBERTWhere2commDouble-MCoCa3D 这篇文章主要想整理一下&#xff0c;根据时间顺序这些文章是怎么说明自己的创新点的&#xff0c;又是怎么说明自己的文章比别的文章优越的。显然似乎很多文章只是…

网络编程:数据库实现增删改

1.数据库实现增删改 程序代码&#xff1a; 1 #include<myhead.h>2 //定义添加数据函数3 int do_add(sqlite3*ppDb)4 {5 //准备sql语句6 int add_numb;//工号7 char add_name[20];//姓名8 double add_salary;9 printf("请输入要添加的工号:&quo…

18-Java迭代器模式 ( Iterator Pattern )

Java迭代器模式 摘要实现范例 迭代器模式&#xff08;Iterator Pattern&#xff09;用于顺序访问集合对象的元素&#xff0c;不需要知道集合对象的底层表示 迭代器模式是 Java 和 .Net 编程环境中非常常用的设计模式 迭代器模式属于行为型模式 摘要 1. 意图 提供一种方法…

sql server使用逗号,分隔保存多个id的一些查询保存

方案一&#xff0c;前后不附加逗号&#xff1a; 方案二&#xff0c;前后附加逗号&#xff1a; 其他保存方案&#xff1a; &#xff08;这里是我做一个程序的商家日期规则搞得&#xff0c;后面再补具体操作&#xff09;&#xff1a; 1,2,3 | 1,2,3 | 1,2,3; 1,2,3 &#xff1…

Unity性能优化篇(十二) 音频优化之导入音频后的属性设置

Unity支持后缀为.wav、.ogg、.mp3的音频文件&#xff0c;但建议使用.wav&#xff0c;因为Unity对它的支持特别好。 注意&#xff1a;Unity在构建项目时总是会自动重新压缩音频文件&#xff0c;因此无需刻意提前压缩一个音频文件再导入Unity&#xff0c;因为这样只会降低该音频文…