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

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

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

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 Spring概述与IoC容器

    • Spring概述与IoC容器
    • Spring Framework 概述
    • IoC 与 DI 核心概念
    • @Configuration 详解
    • @Component 详解
    • @ComponentScan 详解
    • @Import 详解
    • @Profile 详解
    • @PropertySource 详解
    • @Service 详解
    • @Repository 详解
  • 第2章 Bean的定义与依赖注入

    • Bean的定义与依赖注入
    • @Bean 详解
    • @Autowired 详解
    • @Qualifier 详解
    • @Primary 详解
    • @Resource 详解
    • @Inject 详解
    • @Named 详解
    • @Value 详解
    • @Scope 详解
    • @Lazy 详解
  • 第3章 Bean生命周期与作用域

    • Bean生命周期与作用域
    • Bean生命周期概述
    • @PostConstruct
    • @PreDestroy
    • InitializingBean
    • DisposableBean
    • BeanPostProcessor
    • BeanFactoryPostProcessor
  • 第4章 AOP面向切面编程

    • AOP面向切面编程
    • AOP核心概念
    • @EnableAspectJAutoProxy
    • @Aspect
    • @Pointcut
    • @Before
    • @After
    • @AfterReturning
    • @AfterThrowing
    • @Around
  • 第5章 数据访问与事务管理

    • 数据访问与事务管理
    • 数据访问概述
    • @EnableTransactionManagement
    • @Transactional
    • @Transactional 的传播行为
    • @Transactional 的隔离级别
    • @Transactional 的回滚规则
    • @Transactional 的超时与只读属性
    • @TransactionalEventListener
  • 第6章 Spring Boot自动配置基础

    • Spring Boot自动配置基础
    • @SpringBootApplication 注解
    • @EnableAutoConfiguration 注解
    • @ConfigurationProperties 注解
    • @ConditionalOnClass 注解
    • @ConditionalOnMissingBean 注解
    • @ConditionalOnProperty 注解
  • 第7章 从容器到Web: Spring MVC导引

    • Spring MVC 导引
  • 第8章 扩展阅读

    • 扩展阅读
    • Spring 事件机制 — ApplicationEvent / ApplicationListener
    • @EventListener
    • SpEL — Spring 表达式语言
    • 校验 Validation — JSR-303 / JSR-380 Bean Validation
    • 类型转换与数据绑定 — Converter / DataBinder
  • 附录

    • Spring Framework 专业术语
    • Spring 核心知识点
    • Spring 面试高频考点
    • Spring 核心注解速查表

@SpringBootApplication 注解

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


定义与作用

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

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

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


适用位置与常用属性

适用位置

@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 定义注册,自动配置则通过 @Conditional 家族注解判断"是否已存在用户自定义的同类 Bean",若存在则优雅退让,避免冲突。


完整示例

场景简述

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

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

操作前:项目目录结构

com.feixiang.student/
├── StudentManagementApplication.java   ← 启动类(当前为空)
├── config/
│   └── RedisConfig.java                ← 手动配置 Redis
├── service/
│   └── StudentService.java             ← @Service
├── repository/
│   └── StudentRepository.java          ← @Repository
└── controller/
    └── StudentController.java          ← @Controller

操作前状态:启动类未标注任何注解,运行 main 方法后容器为空,所有组件均未被注册。

// 操作前:启动类(错误示范)
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 的能力(@Configuration 的能力由 @SpringBootApplication 隐式提供,但其他配置类仍需独立标注):

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. @Configuration 生效: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 由哪三个注解组成?能否只用一个替代?

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

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

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

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

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

上一页
Spring Boot自动配置基础
下一页
@EnableAutoConfiguration 注解