Spring Boot 中的自动配置原理

2025/4/6

向全栈工程师迈进!

一、自动配置

所谓的自动配置原理就是遵循约定大约配置的原则,在boot工程程序启动后,起步依赖中的一些bean对象会自动的注入到IOC容器中。

在讲解Spring Boot 中bean对象的管理的时候,我们注入bean对象的过程如下,但这种方式不是自动注入的。 

并没有达到自动配置。 而自动配置是当程序在引入spring-boot-starter-web 起步依赖,boot工程在启动后,会自动往ioc容器中注入DispatcherServlet等bean对象,这就是自动配置。那自动配置的原理是什么呢?

二、自动配置原理

在这里只先引入springboot起步核心依赖,而并没有引入spring-boot-starter-web起步依赖。

<!--引入springboot起步核心依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency>

在没有引入spring-boot-starter-web依赖之前,我们尝试输出spring-boot-starter-web起步依赖会自动注入的bean对象,没有在pom.xml文件中添加改起步依赖时,输出发现根本没有。

package com.example.demo;import org.springframework.context.ApplicationContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Demo1Application {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(Demo1Application.class, args);System.out.println(context.getBean("dispatcherServlet"));}}

导入依赖spring-boot-starter-web后,再次尝试输出其bean对象,发现成功,当引入依赖后,其bean对象被自动的注入了。

2.1 查看@SpringBootApplication注解源码

是组合了以下三个注解

  • @SpringBootConfiguration 其本身也是一个组合注解
  • @EnableAutoConfiguration 其本身也是一个组合注解
  • @ComponentScan 是Bean扫描的注解

@SpringBootConfiguration的内部代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Indexed;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}

可以发现在@SpringBootConfiguration内部也是有@Configuration注解的,所以当在启动类上添加注解@SpringBootApplication其实就是也在启动类上添加了@Configuration注解,所以启动类也是一个配置类。

@EnableAutoConfiguration的内部代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot.autoconfigure;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}

@EnableAutoConfiguration是自动配置的核心注解,该@EnableAutoConfiguration注解其实组合了@AutoConfigurationPackage和@Import两个注解,在@Import注解中导入实现类AutoConfigurationImportSelector。其AutoConfigurationImportSelector的实现类如下(代码不全):

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot.autoconfigure;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
........
import org.springframework.util.StringUtils;public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();private static final String[] NO_IMPORTS = new String[0];private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";private ConfigurableListableBeanFactory beanFactory;private Environment environment;private ClassLoader beanClassLoader;private ResourceLoader resourceLoader;private ConfigurationClassFilter configurationClassFilter;public AutoConfigurationImportSelector() {}............private MetadataReaderFactory getMetadataReaderFactory() {try {return (MetadataReaderFactory)this.beanFactory.getBean("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory", MetadataReaderFactory.class);} catch (NoSuchBeanDefinitionException var2) {return new CachingMetadataReaderFactory(this.resourceLoader);}}}
}

 可以发现在这个实现类(AutoConfigurationImportSelector)中,会从 META-INF/spring.factories 文件中读取所有自动配置类,它读取的 key 是:

org.springframework.boot.autoconfigure.EnableAutoConfiguration

加载所有配置类,条件匹配后注册为 Bean。

2.2 自动配置原理——举个栗子🧩

核心:

AutoConfigurationImportSelector 会从 META-INF/spring.factories 文件中读取所有自动配置类,它读取的 key 是:org.springframework.boot.autoconfigure.EnableAutoConfiguration

你写了一个 Spring Boot 项目,启动类是这样的:

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

 这个注解其实包含了 @EnableAutoConfiguration,表示:

“嘿 SpringBoot,我想用你自动帮我配置一些常见功能,比如数据库、Web、Redis 等!”

 🧠 那 SpringBoot 是怎么知道你要配置啥的?

这时候就轮到 AutoConfigurationImportSelector 出场了!

它是一个“选择器”,全名叫:

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector

它的作用是:

🧭“我去找一个叫 spring.factories 的文件,里面写了:SpringBoot 应该自动配置哪些类。我一个个加载它们,看看哪个需要用,哪个可以跳过。”

📂 spring.factories 是什么?

它是一个纯文本配置文件,路径在:

classpath:/META-INF/spring.factories

这个文件来自哪个 jar 包?👉 就是 Spring Boot 的依赖包之一:

spring-boot-autoconfigure-xxx.jar

打开看一下这个文件长什么样:

# 配置项的 key
org.springframework.boot.autoconfigure.EnableAutoConfiguration=# 配置的值(每一行都是一个自动配置类,全限定类名)
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration

🌟 所以:Spring Boot 会遍历所有这些类,一个个判断:

  • 项目中有没有用到数据库?

  • 类路径中有没有 MySQL 驱动?

  • 你有没有配置 spring.datasource.url

  • 有没有你自己写的 DataSource Bean?

满足这些条件它就帮你创建这个 Bean;不满足,它就跳过。

 如下是我真实项目中其spring.factories文件中的内容。

三、实现自动配置 

自动配置全过程如下:

 

山高路远,我们慢些走,路边有花,远处有彩虹,西边有落日...... 

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

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

相关文章

Mysql8配置文件

Mysql8配置文件 修改my.cnf----配置持久化键(persistence key)配置表名不区分大小写 修改my.cnf----配置持久化键(persistence key) MySQL8初始化数据库之前配置好这些变量值&#xff0c;初始化数据库之后可能无法修改这个值。 # 服务端配置 [mysqld] ######## 数据目录和基…

关于系统架构思考,如何设计实现系统的高可用?

绪论、系统高可用的必要性 系统高可用为了保持业务连续性保障&#xff0c;以及停机成本量化&#xff0c;比如在以前的双十一当天如果出现宕机&#xff0c;那将会损失多少钱&#xff1f;比如最近几年Amazon 2021年30分钟宕机损失$5.6M。当然也有成功的案例&#xff0c;比如异地…

【Unity笔记】实现可视化配置的Unity按键输入管理器(按下/长按/松开事件 + UnityEvent绑定)

【Unity笔记】实现可视化配置的Unity按键输入管理器 适用于角色控制、技能触发的Unity按键输入系统&#xff0c;支持UnityEvent事件绑定、长按/松开监听与启用开关 一、引言 在 Unity 游戏开发中&#xff0c;处理键盘输入是最常见的交互方式之一。尤其是角色控制、技能释放、菜…

Fortran 中使用 C_LOC 和 C_F_POINTER 结合的方法来实现不同类型指针指向同一块内存区域

在 Fortran 中&#xff0c;可以使用 C_LOC 和 C_F_POINTER 结合的方法来实现不同类型指针指向同一块内存区域。以下是具体方法和示例&#xff1a; 关键步骤&#xff1a; 获取内存地址&#xff1a;用 C_LOC 获取原始数组的 C 地址。类型转换&#xff1a;用 C_F_POINTER 将地址转…

Spring Boot整合Kafka的详细步骤

1. 安装Kafka 下载Kafka&#xff1a;从Kafka官网下载最新版本的Kafka。 解压并启动&#xff1a; 解压Kafka文件后&#xff0c;进入bin目录。 启动ZooKeeper&#xff1a;./zookeeper-server-start.sh ../config/zookeeper.properties。 启动Kafka&#xff1a;./kafka-server-…

【含文档+PPT+源码】基于微信小程序的学校体育馆操场预约系统的设计与实现

课程简介&#xff1a; 本课程演示的是一款基于微信小程序的学校体育馆操场预约系统的设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从…

【Leetcode-Hot100】最大子数组和

题目 解答 class Solution(object):def maxSubArray(self, nums):""":type nums: List[int]:rtype: int"""len_nums len(nums)result -1e5left_fit, right_fit 0, len_nums-1if len_nums 1:return nums[0]sum_left, sum_right 0, 0while r…

txt、Csv、Excel、JSON、SQL文件读取(Python)

txt、Csv、Excel、JSON、SQL文件读取&#xff08;Python&#xff09; txt文件读写 创建一个txt文件 fopen(rtext.txt,r,encodingutf-8) sf.read() f.close() print(s)open( )是打开文件的方法 text.txt’文件名 在同一个文件夹下所以可以省略路径 如果不在同一个文件夹下 ‘…

硬件电路设计之51单片机(2)

声明&#xff1a;绘制原理图和PCB的软件为嘉立创EDA。根据B站尚硅谷嵌入式之原理图&PCB设计教程学习所作个人用笔记。 目录 一、原理图详解 1、TypeC接口 &#xff08;1&#xff09;TypeC接口介绍 &#xff08;2&#xff09;TypeC原理图 2、5V转3.3V 3、单片机电源开…

kubernetes 入门篇之架构介绍

经过前段时间的学习和实践&#xff0c;对k8s的架构有了一个大致的理解。 1. k8s 分层架构 架构层级核心组件控制平面层etcd、API Server、Scheduler、Controller Manager工作节点层Kubelet、Kube-proxy、CRI&#xff08;容器运行时接口&#xff09;、CNI&#xff08;网络插件&…

Flink CDC 出现错误码 1236 和 SQL 状态 HY000 的原因及解决方法

Flink CDC 出现错误码 1236 和 SQL 状态 HY000 的原因及解决方法 常见原因 server-id 冲突:当多个 Flink CDC 任务连接同一个 MySQL 实例,且使用了相同的 server-id 时,会导致该冲突。因为 MySQL 服务器通过 server-id 来区分不同的从服务器,如果多个 Flink CDC 任务使用相…

从PPT到PNG:Python实现的高效PPT转图工具

从PPT到PNG&#xff1a;Python实现的高效PPT转图工具 在日常工作中&#xff0c;PPT&#xff08;PowerPoint&#xff09;文件是我们常用的演示工具。然而&#xff0c;有时候我们需要将PPT的内容提取为图片格式&#xff08;如PNG&#xff09;以便于展示或保存。手动将每一页PPT保…

【开发语言】悬空指针问题

悬空指针&#xff08;Dangling Pointer&#xff09;是编程中常见的内存管理问题&#xff0c;尤其在C/C这类手动管理内存的语言中。以下是详细解释&#xff1a; 什么是悬空指针&#xff1f; 悬空指针是指向已经被释放&#xff08;或失效&#xff09;内存的指针。这段内存可能已…

【持续更新中】常用docker服务部署指北

前言 docker是个好东西&#xff0c;小树莓派上也能快速部署&#xff0c;方便管理环境。用这篇笔记来记录下各种软件的快速部署方式 准备环境 docker安装 curl -fsSL https://get.docker.com -o get-docker.sh sh ./get-docker.shdocker镜像源配置 一种方法是设置proxy&…

Godot学习-创建简单动画

文章目录 1、准备工作Godot资源 2、创建项目3、创建结点4、创建动画1、创建动画2、添加轨道3、创建关键帧3.1 第一个关键帧3.2 第二个关键帧 5、加载后自动播放6、动画循环7、轨道设置1、轨道更新模式2、轨迹插值3、其他属性的关键帧4、编辑关键帧5、使用 RESET 轨道6、洋葱皮 …

Python 爬虫解决 GBK乱码问题

文章目录 前言爬取初尝试与乱码问题编码知识科普UTF - 8GBKUnicode Python中的编码转换其他编码补充知识GBKGB18030GB2312UTF&#xff08;UCS Transfer Format&#xff09;Unicode 总结 前言 在Python爬虫的过程中&#xff0c;我尝试爬取一本小说&#xff0c;遇到GBK乱码问题&a…

B站搜索关键词机制深度解析:算法逻辑与优化策略

在拥有超过5亿用户的B站生态系统中&#xff0c;每天都有海量的视频内容被上传和消费。对于创作者而言&#xff0c;如何让自己的视频在茫茫内容海洋中被目标受众发现&#xff0c;是至关重要的课题。而关键词&#xff0c;正是连接内容与用户的关键桥梁。理解B站的搜索关键词机制&…

宝塔面板中解锁Laravel日志查看的奥秘

目录 一、前言二、Laravel 日志基础认知2.1 日志的作用2.2 Laravel 日志的默认配置 三、查找 Laravel 日志文件位置3.1 常规存储路径3.2 自定义路径查找 四、查看 Laravel 日志内容4.1 宝塔面板文件管理器查看4.2 使用命令行查看 五、常见问题及解决方法5.1 权限不足无法查看5.…

Matlab Add Legend To Graph-图例添加到图

Add Legeng To Graph: Matlab的legend&#xff08;&#xff09;函数-图例添加到图 将图例添加到图 ,图例是标记绘制在图上的数据序列的有用方法。 下列示例说明如何创建图例并进行一些常见修改&#xff0c;例如更改位置、设置字体大小以及添加标题。您还可以创建具有多列的图…

K8S+Prometheus+Consul+alertWebhook实现全链路服务自动发现与监控、告警配置实战

系列文章目录 k8s服务注册到consul prometheus监控标签 文章目录 系列文章目录前言一、环境二、Prometheus部署1.下载2.部署3.验证 三、kube-prometheus添加自定义监控项1.准备yaml文件2.创建新的secret并应用到prometheus3.将yaml文件应用到集群4.重启prometheus-k8s pod5.访…