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

Spring Boot自动配置原理深度解析:从条件注解到spring.factories

大家好!今天我们来深入探讨Spring Boot最神奇的特性之一——自动配置(Auto-configuration)。这个功能让Spring Boot如此受欢迎,因为它大大简化了我们的开发工作。让我们一起来揭开它的神秘面纱吧!👀

🌟 什么是自动配置?

想象一下,你刚搬进一个新家🏠。如果是传统Spring,你需要自己买家具、安装电器、布置每个房间。而Spring Boot就像一家提供"精装修"服务的公司——当你搬进去时,冰箱🍔、洗衣机👕、电视📺都已经安装好了,而且都是根据你的生活习惯智能选择的!

这就是自动配置的魔力✨——它根据你项目中的依赖和配置,自动为你配置好Spring应用所需的大部分组件。

�️ 自动配置的核心原理

自动配置的实现依赖于几个关键技术和概念:

1. @EnableAutoConfiguration注解

这是启动自动配置的"开关"🔛。当你在主类上使用@SpringBootApplication时,它实际上包含了@EnableAutoConfiguration

@SpringBootApplication  // 这里面就包含了@EnableAutoConfiguration
public class MyApp {public static void main(String[] args) {SpringApplication.run(MyApp.class, args);}
}

2. spring.factories文件

这是自动配置的"地图"🗺️。Spring Boot在META-INF/spring.factories文件中查找所有自动配置类。

# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration,\
com.example.AnotherAutoConfiguration

3. 条件注解(Conditional Annotations)

这些是自动配置的"决策大脑"🧠,决定是否应该应用某个配置。常见的条件注解包括:

  • @ConditionalOnClass:当类路径上有指定类时生效
  • @ConditionalOnMissingBean:当容器中没有指定Bean时生效
  • @ConditionalOnProperty:当配置属性满足条件时生效
  • @ConditionalOnWebApplication:当是Web应用时生效

🔬 深入自动配置流程

让我们看看Spring Boot是如何实现自动配置的:

  1. 启动阶段🚦:

    • Spring Boot应用启动
    • @SpringBootApplication触发自动配置
  2. 加载自动配置类📦:

    • Spring Boot扫描所有jar包中的META-INF/spring.factories文件
    • 加载org.springframework.boot.autoconfigure.EnableAutoConfiguration键下所有的配置类
  3. 过滤自动配置类🧹:

    • 根据各种条件注解过滤掉不适用的配置类
    • 只保留符合条件的配置类
  4. 应用配置⚙️:

    • 将最终筛选出的配置类应用到Spring容器中
    • 创建并注册各种Bean

🧩 条件注解详解

条件注解是自动配置的核心机制,让我们详细看看几个重要的:

@ConditionalOnClass

@Configuration
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration {// 只有当DataSource类在类路径上时,这个配置才会生效
}

@ConditionalOnMissingBean

@Bean
@ConditionalOnMissingBean
public MyService myService() {// 只有当容器中没有MyService类型的Bean时,才会创建这个默认的MyServicereturn new DefaultMyService();
}

@ConditionalOnProperty

@Configuration
@ConditionalOnProperty(prefix = "myapp", name = "enabled", havingValue = "true")
public class MyAppAutoConfiguration {// 只有当myapp.enabled=true时,这个配置才会生效
}

@ConditionalOnWebApplication

@Configuration
@ConditionalOnWebApplication
public class WebMvcAutoConfiguration {// 只有当应用是Web应用时,这个配置才会生效
}

🛠️ 自动配置实战:自定义Starter

理解了原理后,让我们动手创建一个自定义的Spring Boot Starter!

1. 创建自动配置模块

@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyServiceProperties.class)
public class MyServiceAutoConfiguration {@Autowiredprivate MyServiceProperties properties;@Bean@ConditionalOnMissingBeanpublic MyService myService() {return new MyService(properties.getPrefix(), properties.getSuffix());}
}

2. 创建配置属性类

@ConfigurationProperties("my.service")
public class MyServiceProperties {private String prefix;private String suffix;// getters and setters
}

3. 注册自动配置类

src/main/resources/META-INF/下创建spring.factories文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyServiceAutoConfiguration

4. 打包发布

现在,其他项目只需要引入你的starter依赖,就可以自动获得MyService的配置了!

🔍 自动配置的调试技巧

有时候我们需要了解为什么某个自动配置没有生效,Spring Boot提供了几种调试方式:

  1. 启用调试日志📝:
    application.properties中添加:

    debug=true
    

    启动时会打印自动配置报告。

  2. 使用ConditionEvaluationReport📊:
    可以通过注入ConditionEvaluationReport来获取详细的条件评估报告。

  3. 使用Spring Boot Actuator👨⚕️:
    /actuator/conditions端点提供了详细的自动配置条件信息。

⚖️ 自动配置的优缺点

优点:

  • 快速启动⚡:无需手动配置大量样板代码
  • 一致性🔄:所有项目使用相同的默认配置
  • 灵活性🧘:可以通过属性文件轻松覆盖默认配置
  • 模块化🧩:每个starter提供一组相关的自动配置

缺点:

  • 黑盒效应📦:新手可能不理解背后的机制
  • 调试困难🐛:当自动配置不符合预期时,可能需要深入理解原理
  • 启动时间⏳:评估大量条件注解可能增加启动时间

🎓 最佳实践

  1. 理解默认配置🧠:
    在使用一个starter前,最好了解它提供了哪些自动配置。

  2. 合理覆盖配置⚖️:
    只在必要时覆盖自动配置,保持一致性。

  3. 创建自己的starter🛠️:
    当有一组相关的配置和Bean时,考虑创建自己的starter。

  4. 利用条件注解🎚️:
    在自己的配置中也使用条件注解,使配置更加灵活。

  5. 监控自动配置👀:
    定期检查自动配置报告,确保配置符合预期。

🌰 实际案例:DataSource自动配置

让我们看一个实际的自动配置例子——DataSourceAutoConfiguration

@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {@Configuration@Conditional(EmbeddedDatabaseCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })@Import(EmbeddedDataSourceConfiguration.class)protected static class EmbeddedDatabaseConfiguration {}@Configuration@Conditional(PooledDataSourceCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,DataSourceConfiguration.Dbcp2.class,DataSourceConfiguration.Generic.class })protected static class PooledDataSourceConfiguration {}// ...
}

这个自动配置类展示了几个关键点:

  1. 只有在类路径上有DataSourceEmbeddedDatabaseType时才生效
  2. 导入了属性配置DataSourceProperties
  3. 根据条件选择嵌入式数据库或连接池数据库
  4. 支持多种连接池实现(Hikari, Tomcat, Dbcp2等)

🕵️ 如何查看生效的自动配置

Spring Boot提供了几种方式来查看哪些自动配置生效了:

  1. 使用Actuator

    curl http://localhost:8080/actuator/conditions
    
  2. 启用调试模式
    在application.properties中添加:

    debug=true
    

    启动时会打印自动配置报告。

  3. 使用Spring Boot Tools
    许多IDE(如IntelliJ IDEA)提供了Spring Boot工具窗口,可以查看自动配置。

🔄 自动配置与显式配置的关系

自动配置并不是要完全取代显式配置,而是与之协同工作:

  1. 自动配置先执行🏃‍♂️:
    Spring Boot会先尝试自动配置

  2. 显式配置可以覆盖自动配置🖌️:
    你的@Bean定义会覆盖自动配置提供的Bean

  3. 条件注解确保灵活性⚖️:
    自动配置通常带有@ConditionalOnMissingBean,允许你提供自己的实现

🧪 测试自动配置

测试自动配置需要特殊考虑:

  1. 使用@SpringBootTest

    @SpringBootTest
    public class MyAutoConfigurationTests {@Autowired(required = false)private MyService myService;@Testpublic void testServiceAutoConfigured() {assertNotNull(myService);}
    }
    
  2. 测试特定条件

    @Test
    public void testConditionalOnClass() {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();EnvironmentTestUtils.addEnvironment(context, "some.property:true");context.register(MyAutoConfiguration.class);context.refresh();assertTrue(context.containsBean("myBean"));
    }
    

🚀 性能优化技巧

自动配置虽然方便,但也可能影响启动性能:

  1. 减少不必要的starter✂️:
    只引入真正需要的starter依赖

  2. 延迟初始化⏸️:
    在application.properties中设置:

    spring.main.lazy-initialization=true
    
  3. 使用@ComponentScan限制🎯:
    精确指定扫描路径,避免不必要的类扫描

  4. 排除自动配置🚫:
    使用@SpringBootApplication的exclude属性:

    @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
    

📚 深入学习资源

如果你想更深入地学习Spring Boot自动配置:

  1. 官方文档📄:
    Spring Boot Auto-configuration Docs

  2. 源码学习👨💻:
    阅读spring-boot-autoconfigure模块的源码

  3. 相关技术🔗:

    • Spring Framework的@Conditional机制
    • Spring的Environment抽象
    • Spring的BeanDefinition体系

🎯 总结

Spring Boot的自动配置是一个强大而复杂的系统,它通过以下方式工作:

  1. 使用@EnableAutoConfiguration触发自动配置过程
  2. 通过spring.factories发现所有潜在的自动配置类
  3. 利用各种条件注解过滤出适用的配置
  4. 将最终筛选出的配置应用到Spring容器中

理解自动配置原理不仅能帮助你更好地使用Spring Boot,还能让你在遇到问题时更快地定位和解决。希望这篇文章能帮助你深入理解这个强大的特性!💪

记住,自动配置的目标是约定优于配置——它提供了一套合理的默认值,但你总是可以根据需要覆盖这些默认值。这就是Spring Boot既强大又灵活的秘密所在!🔑

Happy coding! 🚀👨💻

推荐阅读文章

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 什么是 Cookie?简单介绍与使用方法

  • 什么是 Session?如何应用?

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • 如何理解应用 Java 多线程与并发编程?

  • 把握Java泛型的艺术:协变、逆变与不可变性一网打尽

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 如何理解线程安全这个概念?

  • 理解 Java 桥接方法

  • Spring 整合嵌入式 Tomcat 容器

  • Tomcat 如何加载 SpringMVC 组件

  • “在什么情况下类需要实现 Serializable,什么情况下又不需要(一)?”

  • “避免序列化灾难:掌握实现 Serializable 的真相!(二)”

  • 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)

  • 解密 Redis:如何通过 IO 多路复用征服高并发挑战!

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”

  • Java 中消除 If-else 技巧总结

  • 线程池的核心参数配置(仅供参考)

  • 【人工智能】聊聊Transformer,深度学习的一股清流(13)

  • Java 枚举的几个常用技巧,你可以试着用用

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • 探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)

  • 为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)

相关文章:

Spring Boot自动配置原理深度解析:从条件注解到spring.factories

大家好!今天我们来深入探讨Spring Boot最神奇的特性之一——自动配置(Auto-configuration)。这个功能让Spring Boot如此受欢迎,因为它大大简化了我们的开发工作。让我们一起来揭开它的神秘面纱吧!👀 🌟 什么是自动配置…...

ubuntu学习day3

3 编译与调试 3.1 gcc/g编译器 当我们进行编译的时候,要使用一系列的工具,我们称之为工具链。SDK就是编译工具链的简写,我们所使用的是gcc系列编译工具链。使用-v参数来查看gcc的版本,从而确定某些语法特性是否可用,…...

C++数据结构与二叉树详解

前言: 在C编程的世界里,数据结构是构建高效程序的基石,而二叉树则是其中最优雅且应用广泛的数据结构之一。本文将带你深入理解二叉树的本质、实现与应用,助你在算法设计中游刃有余。 一、二叉树的基本概念 1. 什么是二叉树 二叉树…...

论文阅读:2023 arxiv Safe RLHF: Safe Reinforcement Learning from Human Feedback

总目录 大模型安全相关研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 Safe RLHF: Safe Reinforcement Learning from Human Feedback https://arxiv.org/pdf/2310.12773 https://github.com/PKU-Alignment/safe-rlhf 速览 研究动机&#xff…...

C++11中的std::condition_variable

一、什么是条件变量? std::condition_variable 是C11标准库中提供的线程同步工具,用于在多线程环境中实现“等待-通知”机制。它的核心作用是让线程能够高效地等待某个条件成立,避免“忙等待”对CPU资源的浪费。 条件变量必须与std::mutex配…...

6.8.最小生成树

一.复习: 1.生成树: 对于一个连通的无向图,假设图中有n个顶点,如果能找到一个符合以下要求的子图: 子图中包含图中所有的顶点,同时各个顶点保持连通, 而且子图的边的数量只有n-1条&#xff0…...

QT中栅格模式探索

1、Qt中选择了栅格模式,如下图所示: 2、在进行整个大的UI界面布局时,需了解每个控件所需要选择的属性sizePolicy。 sizePolicy包含如下几种选择: 3、举个例子:此时整个UI界面,我采用了栅格模式&#xf…...

SLAM | 激光SLAM中的退化问题

在激光SLAM中,判断退化环境的核心是通过数学建模分析环境特征对位姿估计的约束能力。除了LOAM中提出的退化因子D外,还存在多种基于表达式和阈值设定的方法。以下是几种典型方法及其实现原理: 1. 协方差矩阵特征值分析 原理:通过分析点云协方差矩阵的特征值分布,判断环境中…...

C++入门基础:命名空间,缺省参数,函数重载,输入输出

命名空间: C语言是基于C语言的,融入了面向对象编程思想,有了很多有用的库,所以接下来我们将学习C如何优化C语言的不足的。 在C/C语言实践中,在全局作用域中变量,函数,类会有很多,这…...

tomcat 的安装与启动

文章目录 tomcat 服务器安装启动本地Tomcat服务器 tomcat 服务器安装 https://tomcat.apache.org/下载 Tomcat 10.0.X 启动本地Tomcat服务器 进入 Tomcat 的 bin...

C 语言中经典的数据结构

在 C 语言中,经典的数据结构通常包括以下几种,每种都有其特定的应用场景和实现方式: 1. 数组(Array) 定义:连续内存空间存储相同类型的数据。 特点:随机访问快(O(1))&am…...

算法-堆+单调栈

堆 首先堆在我们的Java中我们的是一个优先队列类 PriorityQueue 然后我们要弄最大堆和最小堆 最大堆&#xff1a; PriorityQueue<Integer> pq new PriorityQueue<Integer>((a, b) -> b - a); 最小堆&#xff1a; PriorityQueue<Integer> pq new P…...

物联网平台管理系统

物联网平台管理系统概述 物联网平台管理系统是物联网架构中的核心枢纽&#xff0c;承担着承上启下的关键作用。它向下连接各类物联网设备&#xff0c;实现设备的接入、管理与控制&#xff1b;向上为应用开发提供统一的数据接口和共性模块工具&#xff0c;支撑起各种丰富多彩的…...

STM32CubeMX-H7-15-SPI通信协议读写W25Q64

前言 SPI&#xff08;Serial Peripheral Interface&#xff09;通信协议是一种高速、全双工、同步的串行通信协议 本篇文章就使用W25Q64模块来学习SPI,包括软件SPI代码的编写&#xff0c;硬件SPI&#xff0c;中断SPI和DMASPI SPI的应用场景和模块 &#xff01;这里是抄AI的&a…...

【软考】论devops在企业信息系统开发中的应用

摘要&#xff1a; 随着互联网的不断发展&#xff0c;各行各业都在建设自己的企业信息系统&#xff0c;而随着业务的不断升级和复杂化&#xff0c;系统的更新迭代速度越来越快&#xff0c;系统也越来越复杂。对于信息系统开发者&#xff0c;架构师&#xff0c;管理者&#xff0c…...

生物化学笔记:医学免疫学原理22 肿瘤及肿瘤治疗

肿瘤及肿瘤治疗 免疫疗法 CAR-T细胞介绍...

JVM考古现场(二十二):降维打击·用二向箔优化内存模型

"警报&#xff01;三维堆内存正在经历二维化坍缩&#xff01;" 我腰间的玄铁令突然震动&#xff0c;在蜀山剑派的量子剑阵中投射出诡异的曼德博分形——这是三体文明发动降维打击的铁证&#xff01; 楔子&#xff1a;二向箔奇点降临 昆仑镜监控日志&#xff1a; // …...

第三阶段面试题

Nginx nginx常用模块以及其功能 proxy模块&#xff0c;进行代理功能 ssl模块&#xff0c;进行HTTPS协议的使用 gzip模块&#xff0c;进行传输数据的压缩 upstream模块&#xff0c;进行反向代理时使用 static模块&#xff0c;静态资源进行访问的模块 cache模块&#xff0…...

操作系统-PV

&#x1f9e0; 背景&#xff1a;为什么会有 PV&#xff1f; 类比&#xff1a;内存&#xff08;生产者&#xff09; 和 CPU&#xff08;消费者&#xff09; 内存 / IO / 磁盘 / 网络下载 → 不断“生产数据” 例如&#xff1a;读取文件、下载视频、从数据库加载信息 CPU → 负…...

nuxt3路由切换页面出不来,刷新可以

nuxt3遇到一个奇怪的现象&#xff1a; 不管是router.push()跳转还是navigateTo()跳转&#xff0c;浏览器url变了&#xff0c;但是页面是空白的&#xff0c;没加载出来&#xff0c;刷新之后页面正常。 解决方案&#xff1a; <template>下的所有内容必须套在一个div里面...

Spring Boot配置文件优先级全解析:如何优雅覆盖默认配置?

&#x1f4da; 一、为什么需要了解配置文件优先级&#xff1f; 想象一下&#xff0c;你正在玩一个游戏&#x1f3ae;&#xff0c;游戏里有默认设置&#xff0c;但你可以通过不同的方式修改这些设置&#xff1a; 游戏内置的默认设置&#xff08;就像Spring Boot的默认配置&…...

医院数据中心智能化数据上报与调数机制设计

针对医院数据中心的智能化数据上报与调数机制设计,需兼顾数据安全性、效率性、合规性及智能化能力。以下为系统性设计方案,分为核心模块、技术架构和关键流程三部分: 一、核心模块设计 1. 数据上报模块 子模块功能描述多源接入层对接HIS/LIS/PACS/EMR等异构系统,支持API/E…...

Linux之基础命令

Linux作为开源操作系统的代表&#xff0c;以其高效、灵活和强大的命令行工具闻名。无论是系统管理、开发调试还是日常使用&#xff0c;掌握基础命令都是与Linux系统交互的必备技能。本文整理了20个最常用的Linux基础命令&#xff0c;帮助新手快速入门。 目录 目录与文件导航文…...

【MATLAB代码例程】AOA与TOA结合的高精度平面地位,适用于四个基站的情况,附完整的代码

本代码实现了一种基于到达角(AOA) 和到达时间(TOA) 的混合定位算法,适用于二维平面内移动或静止目标的定位。通过4个基站的协同测量,结合最小二乘法和几何解算,能够有效估计目标位置,并支持噪声模拟、误差分析和可视化输出。适用于室内定位、无人机导航、工业监测等场景…...

PC主板及CPU ID 信息、笔记本电脑唯一 MAC地址获取

&#x1f947; 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 &#x1f389; 声明: 作为全网 AI 领域 干货最多的博主之一&#xff0c;❤️ 不负光阴不负卿 ❤️ 文章目录 PC主板及CPU ID 信息物理 MAC地址获取win11 新电脑 wmic 安装❤️ 欢迎一起学AI…...

RK3568笔记八十二: 利用AI生成的简单数据转发服务程序

若该文为原创文章,转载请注明原文出处。 测试AI编写代码能力,做了个简单的数据转发功能,后期想部署到服务器 功能相对简单,大概功能如下: 1、打开TCP服务端,等待客户端连接 2、客户端连接后发送ID:1234格式,服务端收到,解析出ID:1234并记录 3、相同的ID数据之间互…...

C++17 信号量模拟实现

C17 信号量模拟实现 一、实现原理 C17 标准库没有原生信号量(C20才有)&#xff0c;但可以通过 std::mutex std::condition_variable 模拟实现。以下是核心逻辑&#xff1a; #include <mutex> #include <condition_variable>class CountingSemaphore { private:…...

web后端语言中篇

#作者&#xff1a;允砸儿 #日期&#xff1a;乙巳青蛇年 三月十八 笔者本来打算隔一天给它更完的&#xff0c;但是事情有点多这几天&#xff0c;实在是抱歉。废话不多说直接进入正题。 PHP流程控制语句 什么是流控:流程控制语句用于决定代码的执行顺序。 #注意流程控制语句…...

Spine-Leaf 与 传统三层架构:全面对比与解析

本文将详细介绍Spine-Leaf架构&#xff0c;深入对比传统三层架构&#xff08;Core、Aggre、Access&#xff09;&#xff0c;并探讨其与Full-mesh网络和软件定义网络&#xff08;SDN&#xff09;的关联。通过通俗易懂的示例和数据中心网络分析&#xff0c;我将帮助您理解Spine-L…...

Vmware esxi 查看硬盘健康状况

起因 硬盘掉盘 - - 使用自带的命令esxcli 列出所有硬盘 esxcli storage core device list[rootlocalhost:~] esxcli storage core device list t10.NVMe____INTEL_MEMPEK1W016GAL____________________PHBT83660BYP016D____00000001Display Name: Local NVMe Disk (t10.NVMe…...