Spring Boot 核心注解全解:@SpringBootApplication背后的三剑客
大家好呀!👋 今天我们要聊一个超级重要的Spring Boot话题 - 那个神奇的主类注解@SpringBootApplication!很多小伙伴可能每天都在用Spring Boot开发项目,但你真的了解这个注解背后的秘密吗?🤔
别担心,今天我就用最通俗易懂的方式,带大家彻底搞懂这个"三合一"的超级注解!保证连小学生都能听懂!🎯 文章会很长很详细,但绝对值得你花时间看完!💪
一、先来认识下主角:@SpringBootApplication
每次我们创建一个Spring Boot项目,都会在主类上看到这个注解:
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
看起来很简单对吧?但你知道吗,这个注解其实是个"三合一"的超级注解!🦸♂️ 它由三个核心注解组合而成:
@SpringBootConfiguration- 配置担当@EnableAutoConfiguration- 自动装配担当@ComponentScan- 组件扫描担当
接下来我们就一个个拆解,看看它们各自有什么本领!🔍
二、第一剑客:@SpringBootConfiguration
1. 基本介绍
@SpringBootConfiguration是Spring Boot特有的配置注解,它实际上是@Configuration注解的"加强版"💪。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}
从代码可以看出,它本质上就是一个@Configuration,但加上了Spring Boot的特殊标识。
2. 它能做什么?
- 标识配置类:告诉Spring"这是一个配置类,里面有Bean的定义哦!"📝
- 定义Bean:可以在类里用
@Bean注解定义各种组件 - 替代XML配置:以前用XML配置的Bean,现在可以用Java代码来配置了
3. 实际使用示例
@SpringBootConfiguration
public class MyConfig {@Beanpublic MyService myService() {return new MyServiceImpl();}@Beanpublic DataSource dataSource() {// 配置数据源return new HikariDataSource();}
}
4. 与@Configuration的区别
虽然功能相同,但@SpringBootConfiguration有特殊含义:
- 它通常只用于主配置类(就是有main方法的那个类)
- Spring Boot在内部处理时会特殊对待它
- 一般项目中建议还是用
@Configuration,除非是主类
5. 小测验
❓ 问题:如果一个类被@SpringBootConfiguration标注,Spring会怎么处理它?
💡 答案:Spring会把它当作配置类处理,扫描其中的@Bean方法,并将返回的对象注册为Spring容器中的Bean。
三、第二剑客:@EnableAutoConfiguration
这是三个剑客中最强大也最神奇的一个!✨ 它开启了Spring Boot的"自动装配"魔法!
1. 自动装配是什么?
想象你去吃自助餐🍽️:
- 传统Spring:你需要自己点每道菜(手动配置每个Bean)
- Spring Boot:看到你走进来,就自动把你可能喜欢的菜都端上来了(自动配置)
这就是自动装配的魅力!它根据你添加的依赖,自动配置Spring应用。
2. 工作原理揭秘
@EnableAutoConfiguration背后的魔法是这样实现的:
- 读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件:这个文件里列出了所有自动配置类
- 条件过滤:根据当前环境(类路径、已有Bean等)过滤掉不适用的配置
- 应用配置:将符合条件的配置类加载进来
3. 自动配置示例
举个例子🌰:
- 你在pom.xml中添加了
spring-boot-starter-data-jpa - Spring Boot看到后:“哦!你需要JPA支持!”
- 自动配置数据源、EntityManager等JPA相关Bean
4. 查看自动配置报告
想知道哪些自动配置生效了?可以这样查看:
在application.properties中添加:
debug=true
启动时会打印类似这样的报告:
=========================
AUTO-CONFIGURATION REPORT
=========================Positive matches:
-----------------DataSourceAutoConfiguration matched:- @ConditionalOnClass found org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType (OnClassCondition)Negative matches:
-----------------ActiveMQAutoConfiguration:Did not match:- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
5. 自定义自动配置
你也可以创建自己的自动配置!步骤:
- 创建
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件 - 写入你的配置类全限定名
- 使用
@Conditional系列注解控制条件
6. 排除自动配置
如果不想要某些自动配置,可以排除它们:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApplication {// ...
}
或者在配置文件中:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
7. 小测验
❓ 问题:为什么我们加了spring-boot-starter-web依赖后,Tomcat就自动启动了?
💡 答案:因为@EnableAutoConfiguration检测到类路径下有Servlet相关的类,自动加载了Tomcat的配置。
四、第三剑客:@ComponentScan
1. 组件扫描是什么?
@ComponentScan就像Spring的"雷达"📡,它会扫描指定包及其子包下的组件(被@Component、@Service、@Repository等注解的类),并把它们注册为Spring Bean。
2. 默认行为
在@SpringBootApplication中,如果没有指定扫描路径:
- 默认扫描主类所在包及其子包
- 这也是为什么我们通常把主类放在项目最外层包
3. 自定义扫描路径
如果你想扫描其他包,可以这样:
@SpringBootApplication
@ComponentScan({"com.myapp", "com.shared"})
public class MyApplication {// ...
}
4. 过滤组件
你可以包含或排除特定组件:
@ComponentScan(basePackages = "com.myapp",excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.myapp.test.*")
)
5. 与XML配置的对比
以前在XML中是这样配置组件扫描的:
现在用注解更加简洁方便!
6. 实际应用技巧
- 组织包结构:合理组织包结构,让扫描更高效
- 避免全盘扫描:不要扫描不必要的包(如第三方jar包)
- 多模块项目:在多模块项目中,注意主类的位置
7. 小测验
❓ 问题:如果把主类放在com.myapp包,但你的Service类在com.service包,会发生什么?
💡 答案:Service类不会被自动扫描到,需要手动添加@ComponentScan("com.service")或者把Service移到com.myapp或其子包下。
五、三剑客如何协同工作
现在我们已经认识了三位剑客,来看看它们是如何配合的:🤝
- 启动阶段:SpringApplication.run()启动时
- @SpringBootConfiguration:先识别这是一个配置类
- @ComponentScan:扫描组件,注册Bean定义
- @EnableAutoConfiguration:根据条件自动配置
- Bean实例化:所有Bean定义就绪后,实例化Bean
它们的执行顺序非常重要!组件扫描要先于自动配置,这样自动配置才能基于已有Bean进行条件判断。
六、深入理解:@SpringBootApplication源码解析
让我们看看这个注解的庐山真面目:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {// 可以指定排除的自动配置类@AliasFor(annotation = EnableAutoConfiguration.class)Class[] exclude() default {};// 可以指定排除的自动配置类名@AliasFor(annotation = EnableAutoConfiguration.class)String[] excludeName() default {};// 可以自定义扫描包@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")String[] scanBasePackages() default {};// 可以自定义扫描类@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")Class[] scanBasePackageClasses() default {};
}
可以看到,它主要是组合了三个注解,并提供了一些便捷的属性来配置它们。
七、实际开发中的最佳实践
1. 主类位置
✅ 正确做法:放在项目最顶层包
com
└── myapp├── Application.java ← 主类在这里├── controller├── service└── repository
❌ 错误做法:放在深层包中
com
└── myapp├── config│ └── Application.java ← 主类放太深了!├── controller├── service└── repository
2. 多模块项目配置
对于多模块项目,可以这样组织:
// 主模块中的主类
@SpringBootApplication
@ComponentScan({"com.myapp.module1","com.myapp.module2","com.myapp.shared"
})
public class MyApplication {// ...
}
3. 自定义配置技巧
- 排除特定自动配置:如测试时排除安全配置
- 精细控制扫描:只扫描必要的包提高性能
- 组合使用:可以同时使用这三个注解进行更细粒度控制
八、常见问题解答
Q1: 为什么我的自定义配置类不生效?
可能原因:
- 没有放在组件扫描的路径下
- 类上没有加
@Configuration或相关注解 - 被其他配置覆盖了
解决方案:
- 检查包结构
- 添加
@Configuration - 使用
@Order调整顺序
Q2: 自动配置太魔法了,如何知道发生了什么?
解决方法:
- 开启debug模式(
debug=true) - 查看
/actuator/conditions端点(需要actuator依赖) - 阅读官方文档的自动配置部分
Q3: 如何覆盖自动配置的Bean?
很简单,只需要自己定义一个同类型的Bean:
@Bean
public DataSource dataSource() {// 你的自定义数据源return new MyCustomDataSource();
}
Spring Boot会优先使用你的Bean而不是自动配置的。
九、高级话题:自定义@SpringBootApplication
你甚至可以创建自己的"增强版"@SpringBootApplication!
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableCaching
@EnableAsync
public @interface MyEnhancedSpringBootApplication {// 可以添加自定义属性
}
然后就可以这样使用:
@MyEnhancedSpringBootApplication
public class MyApplication {// ...
}
这样就把缓存和异步支持也默认集成了!
十、总结回顾
今天我们深入剖析了@SpringBootApplication背后的三位剑客:
- @SpringBootConfiguration - 标识这是一个配置类
- @EnableAutoConfiguration - 开启自动配置魔法
- @ComponentScan - 自动扫描组件
记住它们的协作关系:
- 先识别配置
- 再扫描组件
- 最后自动配置
理解这些核心注解的工作原理,能让你更好地掌握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 核心注解全解:@SpringBootApplication背后的三剑客
大家好呀!👋 今天我们要聊一个超级重要的Spring Boot话题 - 那个神奇的主类注解SpringBootApplication!很多小伙伴可能每天都在用Spring Boot开发项目,但你真的了解这个注解背后的秘密吗?🤔 别担心&#x…...
【Python爬虫基础篇】--1.基础概念
目录 1.爬虫--定义 2.爬虫--组成 3.爬虫--URL 1.爬虫--定义 网络爬虫,是一种按照一定规则,自动抓取互联网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。随着网络的迅速发展,万维网成为大量信息的载体…...
CSS进度条带斑马纹动画(有效果图)
效果图 .wxml <view class"tb"><view class"tb-line" style"transform:translateX({{w%}})" /> </view> <button bind:tap"updateLine">增加进度</button>.js Page({data: {w:0,},updateLine(){this.…...
文件二进制读写和文本读写以及编码解码
假如是utf8编码,windows系统 写:往键盘中写的字符会被utf8编码成字节写入文件。假如是文本写,\n会被替换为\r\n写入,结尾会加文件结束符EOF。假如是二进制写,\n就是\n,文件结尾也不会加什么EOF 读ÿ…...
HarmonyOS:使用Refresh组件实现页面下拉刷新上拉加载更多
一、前言 可以进行页面下拉操作并显示刷新动效的容器组件。 说明 该组件从API Version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。该组件从API Version 12开始支持与垂直滚动的Swiper和Web的联动。当Swiper设置loop属性为true时&…...
获取印度股票市场列表、查询IPO信息以及通过WebSocket实时接收数据
为了对接印度股票市场,获取市场列表、查询IPO信息、查看涨跌排行榜以及通过WebSocket实时接收数据等步骤。 1. 获取市场列表 首先,您需要获取支持的市场列表,这有助于了解哪些市场可以交易或监控。 请求方法:GETURL:…...
【C++深入系列】:模版详解(上)
🔥 本文专栏:c 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 你不需要很厉害才能开始,但你需要开始才能很厉害。 ★★★ 本文前置知识: 类和对象(上) …...
leetcode刷题日记——同构字符串
[ 题目描述 ]: [ 思路 ]: 题目要求判断 s 和 t 是否为同构字符串,即 s 中每个字符与 t 中对应位置的字符形成一个映射关系,且只能是一对一映射ASCII(American Standard Code for Information Interchange)…...
HTTP/1.1 队头堵塞问题
文章目录 一、队头堵塞1、非管线化2、管线化 二、如何解决? 一、队头堵塞 1、非管线化 如图,http 请求必须等到上一个请求响应后才能发送,后面的以此类推,由此可以看出,在一个 tcp 通道中,如果某个 http 请…...
【Quest开发】在虚拟世界设置具有遮挡关系的透视窗口
软件:Unity 2022.3.51f1c1、vscode、Meta XR All in One SDK V72 硬件:Meta Quest3 仅针对urp管线 参考了YY老师这篇,可以先看他的再看这个可能更好理解一些:Unity Meta Quest MR 开发(七):使…...
Qt界面卡住变慢的解决方法
本质原因: 当Qt界面出现卡顿或无响应时,通常是因为主线程(GUI线程)被耗时操作阻塞。 完全忘了。。。 Qt Creater解决方法 1. 定位耗时操作 目标:找到阻塞主线程的代码段。 方法: 使用QElapsedTimer测量代码执行时间…...
常用 Git 命令详解
Git 是一个强大的版本控制工具,广泛用于软件开发和团队协作中。掌握 Git 命令可以帮助开发者更高效地管理代码版本和项目进度。本文将介绍一些常用的 Git 命令,并提供示例以帮助你更好地理解和应用这些命令。 目录 常用命令 git clonegit stashgit pul…...
java导出word含表格并且带图片
背景 我们需要通过 Java 动态导出 Word 文档,基于预定义的 模板文件(如 .docx 格式)。模板中包含 表格,程序需要完成以下操作: 替换模板中的文本(如占位符 ${设备类型} 等)。 替换模板中的图…...
基于CNN卷积神经网络和GEI步态能量提取的视频人物步态识别算法matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 GEI步态能量提取 4.2 CNN卷积神经网络原理 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2024b/matlab2022a 3.部分核心程序 &…...
【Pandas】pandas DataFrame isin
Pandas2.2 DataFrame Indexing, iteration 方法描述DataFrame.head([n])用于返回 DataFrame 的前几行DataFrame.at快速访问和修改 DataFrame 中单个值的方法DataFrame.iat快速访问和修改 DataFrame 中单个值的方法DataFrame.loc用于基于标签(行标签和列标签&#…...
算法思想之链表
欢迎拜访:雾里看山-CSDN博客 本篇主题:算法思想之链表 发布时间:2025.4.18 隶属专栏:算法 目录 算法介绍常用技巧 例题两数相加题目链接题目描述算法思路代码实现 两两交换链表中的节点题目链接题目描述算法思路代码实现 重排链表…...
Oceanbase单机版上手示例
本月初Oceanbase单机版发布,作为一个以分布式起家的数据库,原来一个集群动辄小十台机器,多着十几台几十台甚至更多,Oceanbase单机版的发布确实大大降低了硬件部署的门槛。 1.下载安装介质 https://www.oceanbase.com/softwarece…...
架构师面试(三十二):注册中心数据结构
问题 提到【注册中心】,我们对它的基本功能,肯定可以顺手拈来,比如:【服务注册】【服务发现】【健康检查】【变更通知】等。 透过这些基本功能,一个普适的注册中心的数据结构应该如何设计呢? 可以结合着…...
《软件设计师》复习笔记(11.5)——测试原则、阶段、测试用例设计、调试
目录 1. 测试基础概念 2. 测试方法分类 3. 测试阶段 真题示例: 题目1 题目2 题目3 4. 测试策略 5. 测试用例设计 真题示例: 6. 调试与度量 真题示例: 1. 测试基础概念 定义:系统测试是为发现错误而执行程序的过程&…...
闲来无事,用HTML+CSS+JS打造一个84键机械键盘模拟器
今天闲来无聊,突发奇想要用前端技术模拟一个机械键盘。说干就干,花了点时间搞出来了这么一个有模有样的84键机械键盘模拟器。来看看效果吧! 升级版的模拟器 屏幕录制 2025-04-18 155308 是不是挺像那么回事的?哈哈! 它…...
23种设计模式全面解析
设计模式是解决软件设计中常见问题的经典方案。根据《设计模式:可复用面向对象软件的基础》(GoF),23种设计模式分为以下三类: 一、创建型模式(5种) 目标:解耦对象的创建过程&#x…...
Java学习手册:常见并发问题及解决方案
在Java并发编程中,开发者常常会遇到各种并发问题,这些问题可能导致程序行为不可预测、性能下降甚至程序崩溃。以下是一些常见的并发问题及其解决方案: 1.竞态条件(Race Condition) 竞态条件是指多个线程同时访问共享…...
【免费下载】中国各省市地图PPT,可编辑改颜色
很多同学做PPT时,涉及到中国地图或省份展示,自己绘制和调色难度大,下面为大家准备了中国地图的可编辑模板,可以根据PPT整体色或想突出的省份,直接调整颜色。 需要这份数据,请在文末查看下载方法。 一、数…...
Linux 系统编程 day4 进程管道
进程间通信(IPC) Linux环境下,进程地址空间相互独立,任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能互相访问,要交换数据必须通过内核,在内核中开辟一块缓冲区…...
【Reading Notes】(8.2)Favorite Articles from 2025 February
【February】 高阶智驾别被短期市占率迷住眼!(2025年02月01日) 2024年,高阶智驾发展迅猛,粗略计算中国市场(特斯拉之外)的城市NOA车型的年度搭载量超过了100万台。但相比于中国乘用车市场2000万…...
探索大语言模型(LLM):循环神经网络的深度解析与实战(RNN、LSTM 与 GRU)
一、循环神经网络(RNN) 1.1 基本原理 循环神经网络之所以得名,是因为它在处理序列数据时,隐藏层的节点之间存在循环连接。这意味着网络能够记住之前时间步的信息,并利用这些信息来处理当前的输入。 想象一下…...
山东大学软件学院创新项目实训开发日志(15)之中医知识问答历史对话查看bug处理后端信息响应成功但前端未获取到
在开发中医知识问答历史对话查看功能的时候,出现了前后端信息获取异同的问题,在经过非常非常非常艰难的查询之后终于解决了这一问题,而这一问题的罪魁祸首就是后端没有setter和getter方法!!!!&a…...
poj1067 取石子游戏 威佐夫博弈
题目 有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法, 一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者…...
优先级队列的实模拟实现
优先级队列底层默认用的是vector来存储数据,实现了类似我们数据结构中学习过的堆的队列,他的插入和删除都是优先级高先插入和删除。下面我们来模拟实现它们常见的接口来熟悉优先级队列。 仿函数 在介绍优先级队列之前,我们先熟悉一个概念&a…...
中国高校光芯片技术进展:前沿突破与产业化路径分析——基于材料、集成与系统协同创新的视角
引言:光电子技术的范式变革 随着摩尔定律逼近物理极限,光芯片技术成为突破电子芯片性能瓶颈的核心路径。光芯片以光子为载体,在传输速率(>100 Gbps)、能耗效率(<1 pJ/bit)及抗电磁干扰等…...
