乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Spring Boot 概述

    • 章节导读:Spring Boot概述与核心理念
    • Spring Boot是什么
    • Spring Boot与Spring Framework的关系
    • 约定优于配置
  • 第2章 快速入门与第一个应用

    • 章节导读:快速入门与第一个应用
    • SpringApplication
    • 第一个Spring Boot应用
  • 第3章 起步依赖与版本管理

    • 章节导读:起步依赖与版本管理
    • 起步依赖
    • BOM版本管理
  • 第4章 自动配置原理

    • 章节导读:自动配置原理
    • 自动配置原理
    • AutoConfigurationImportSelector
    • 自动配置报告
  • 第5章 核心注解

    • 章节导读:核心注解
    • @SpringBootApplication
    • @EnableAutoConfiguration
    • @ConditionalOnClass
    • @ConditionalOnMissingBean
    • @ConditionalOnBean
    • @ConditionalOnProperty
  • 第6章 外部化配置与属性绑定

    • 章节导读:外部化配置与属性绑定
    • 外部化配置
    • @ConfigurationProperties
    • @Value
    • 配置属性优先级
  • 第7章 Profile 与环境切换

    • 章节导读:Profile与环境切换
    • @Profile
    • 多环境配置文件
  • 第8章 内嵌服务器与部署

    • 章节导读:内嵌服务器与部署
    • 内嵌服务器
    • Fat Jar
  • 第9章 Actuator 与监控

    • 章节导读:Actuator与监控
    • Actuator Health
    • Actuator Info
    • Actuator Metrics
    • 自定义Endpoint
    • 自定义HealthIndicator
  • 第10章 开发工具与最佳实践

    • 章节导读:开发工具与最佳实践
    • Banner自定义
    • 热部署

一句话定位:@SpringBootApplication 是 Spring Boot 应用的三合一入口印章,它将 @Configuration(配置类)、@EnableAutoConfiguration(自动配置引擎)和 @ComponentScan(组件扫描)三大能力聚合为一枚注解,是每个 Spring Boot 项目启动类头顶不可或缺的标识。


定义与作用

@SpringBootApplication 是一个组合注解(Composite Annotation),由以下三个核心注解聚合而成:

组成注解独立作用在本注解中的角色
@SpringBootConfiguration等价于 @Configuration,声明当前类为配置类提供显式配置能力
@EnableAutoConfiguration开启自动配置机制,根据类路径和配置自动注册 Bean提供自动装配能力
@ComponentScan开启组件扫描,自动发现并注册 @Component 及其派生注解标记的类提供组件发现能力

在 Spring Boot 2.7.x 中,@SpringBootApplication 的源码定义等价于同时标注上述三个注解。它的设计意图是约定优于配置——开发者只需在启动类上贴一个注解,即可获得一个功能完备的 Spring 应用上下文。

对比传统 Spring Framework:

维度传统 Spring FrameworkSpring Boot + @SpringBootApplication
配置类声明手动标注 @Configuration通过 @SpringBootConfiguration 隐式提供
自动配置无,需手动写所有基础设施 Bean通过 @EnableAutoConfiguration 自动装配
组件扫描手动声明 @ComponentScan 并指定包路径默认扫描当前包及子包
启动类代码量3 个注解 + 包路径配置1 个注解

适用位置与常用属性

适用位置

@SpringBootApplication 只能标注在类级别,且通常只出现在主启动类上。一个标准的 Spring Boot 项目有且仅有一个主启动类。

package com.feixiang.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

常用属性

@SpringBootApplication 本身不直接定义属性,而是通过元注解暴露其组成注解的属性:

属性来源元注解说明典型用法
scanBasePackages@ComponentScan指定组件扫描的根包路径@SpringBootApplication(scanBasePackages = "com.feixiang")
scanBasePackageClasses@ComponentScan以指定类所在包为扫描根@SpringBootApplication(scanBasePackageClasses = StudentService.class)
exclude@EnableAutoConfiguration排除特定的自动配置类@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
excludeName@EnableAutoConfiguration按类名排除自动配置@SpringBootApplication(excludeName = "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration")

重要:scanBasePackages 的默认值是当前类所在包及其子包。如果启动类放在根包(如 com.feixiang),而业务代码分散在其他同级包(如 com.xxx),则必须显式指定 scanBasePackages,否则组件扫描会遗漏。


核心原理

组合注解的拆解与执行时序

当 Spring Boot 启动时,SpringApplication.run() 会解析主启动类上的 @SpringBootApplication,并将其拆解为三个独立的注解依次处理:

三大能力的协作关系

执行优先级:组件扫描和显式配置先于自动配置完成 Bean 定义注册(因为 AutoConfigurationImportSelector 实现 DeferredImportSelector,延迟处理),自动配置则通过 @Conditional 家族注解判断"是否已存在用户自定义的同类 Bean",若存在则优雅退让,避免冲突。


完整示例

场景简述

飞翔科技公司(广州)的技术部正在开发一套学生成绩管理系统。架构师白歌要求后端开发小崔搭建项目骨架。小崔需要创建一个 Spring Boot 启动类,使得:

  1. 项目能扫描到 com.feixiang.student 包下的所有业务组件(Service、Repository、Controller)
  2. 自动配置数据源和 Web MVC 环境
  3. 同时保留手动配置 Redis 连接的能力
  4. 排除 MongoDB 自动配置(因为 student_db 使用 MySQL)

操作前:未标注的启动类

// 操作前:启动类(错误示范)
package com.feixiang.student;

public class StudentManagementApplication {
    public static void main(String[] args) {
        // 没有 SpringApplication.run,这只是一个普通 Java 程序
        System.out.println("Hello, 飞翔科技!");
    }
}

运行结果:

Hello, 飞翔科技!
Process finished with exit code 0

此时没有任何 Spring 容器被创建,StudentService、StudentRepository 均未被实例化。

使用该注解的完整代码

小崔在架构师白歌的指导下,将启动类改写为标准的 Spring Boot 启动类:

package com.feixiang.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 飞翔科技学生成绩管理系统启动类
 * 
 * @author 小崔
 * @since 2024
 */
@SpringBootApplication(
    scanBasePackages = "com.feixiang.student",
    exclude = {
        // 排除 Mongo 自动配置,因为本项目使用 MySQL
        org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration.class
    }
)
public class StudentManagementApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudentManagementApplication.class, args);
    }
}

同时,在 config 包下保留手动配置 Redis 的能力:

package com.feixiang.student.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

@Configuration
public class RedisConfig {
    
    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }
}

业务组件正常标注:

package com.feixiang.student.service;

import org.springframework.stereotype.Service;

@Service
public class StudentService {
    public String queryScore(Long studentId) {
        return "学生 " + studentId + " 的成绩查询结果";
    }
}

操作后运行结果及分析

启动应用后,控制台输出关键日志:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.7.18)

2024-05-20 09:15:32.123  INFO 12345 --- [main] c.f.s.StudentManagementApplication : Starting StudentManagementApplication using Java 1.8 on DESKTOP-FEIXIANG
2024-05-20 09:15:32.456  INFO 12345 --- [main] c.f.s.StudentManagementApplication : No active profile set, falling back to default profiles: default
2024-05-20 09:15:33.789  INFO 12345 --- [main] .s.d.r.c.RepositoryComponentSupport : No Spring Data JPA repositories found.
2024-05-20 09:15:34.012  INFO 12345 --- [main] o.s.b.w.e.t.TomcatWebServer          : Tomcat started on port(s): 8080 (http)
2024-05-20 09:15:34.123  INFO 12345 --- [main] c.f.s.StudentManagementApplication : Started StudentManagementApplication in 2.345 seconds

分析:

  1. @SpringBootConfiguration 生效:StudentManagementApplication 自身被注册为配置类,虽然启动类通常不写 @Bean 方法,但它具备这个能力。
  2. @EnableAutoConfiguration 生效:Tomcat 自动启动(TomcatWebServer 日志)、数据源自动配置被触发(因类路径存在 spring-jdbc 和 HikariCP)。
  3. @ComponentScan 生效:StudentService、StudentRepository、StudentController 均被扫描并注册为 Bean。
  4. exclude 生效:MongoAutoConfiguration 被排除,避免了无 MongoDB 环境时的报错。

易错场景与面试考点

易错场景一:启动类放错包导致扫描遗漏

小崔曾犯过一个经典错误:把启动类放在 com.feixiang.student.config 包下,而业务代码在 com.feixiang.student.service 包下。

// 错误示范:启动类放在子包中
package com.feixiang.student.config;

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

后果:@ComponentScan 默认扫描 com.feixiang.student.config 及其子包,com.feixiang.student.service 与其是同级包而非子包,因此 StudentService、StudentController 全部遗漏。启动后访问接口报 404,小崔排查了半小时才发现是包结构问题。

正确做法:启动类必须放在根包(如 com.feixiang.student),或显式指定 scanBasePackages = "com.feixiang"。

易错场景二:试图在多个类上同时使用

// 错误示范:两个类都标注 @SpringBootApplication
package com.feixiang.student;

@SpringBootApplication
public class StudentManagementApplication { ... }

@SpringBootApplication  // ← 错误!
public class AdminModuleApplication { ... }

后果:Spring Boot 设计上期望单一入口。虽然技术上可以运行,但会导致组件扫描范围混乱、自动配置重复执行、配置属性加载冲突等问题。

面试考点

Q:@SpringBootApplication 由哪三个注解组成?能否只用一个替代?

由 @SpringBootConfiguration(等价于 @Configuration)、@EnableAutoConfiguration、@ComponentScan 组成。可以手动分别标注这三个注解达到完全等价的效果,但 @SpringBootApplication 是约定俗成的标准写法,且提供了 exclude 等便捷属性。

Q:如果项目中有多个同级模块,启动类如何确保扫描到所有 Bean?

使用 scanBasePackages 显式指定共同的父包,例如 @SpringBootApplication(scanBasePackages = "com.feixiang")。或者将启动类上移至根包。

Q:@SpringBootApplication 的 exclude 和 excludeName 有什么区别?

exclude 接收 Class<?> 数组,编译期类型安全;excludeName 接收字符串类名数组,用于在类路径不可达时(如避免循环依赖)排除配置。

Q:为什么 @SpringBootApplication 中 @EnableAutoConfiguration 的处理是"延迟"的?

因为 AutoConfigurationImportSelector 实现了 DeferredImportSelector,它会在所有普通 @Configuration 和 @ComponentScan 处理完毕后才执行。这确保了用户自定义的 Bean 先于自动配置被注册,从而让 @ConditionalOnMissingBean 能够正确判断"用户是否已经自定义了同类 Bean",实现"用户配置优先"的退让机制。

上一页
章节导读:核心注解
下一页
@EnableAutoConfiguration