SpringBoot 常用注解详细解析
作者:莫寒清
一句话总结
- 整体记忆:启动靠
@SpringBootApplication,IOC 靠组件注解 +@Autowired,配置靠@Value/@ConfigurationProperties,Web 层靠@RestController+ 各种@xxxMapping,扩展能力靠@Enable系列,细节控制靠条件装配和事务、校验等注解。 - 面试常问:
@SpringBootApplication里面包含了什么?@RestController和@Controller的区别?@Autowired和@Resource的区别?@ConfigurationProperties和@Value的区别及使用场景?- 自动装配是如何依赖
@ConditionalOnXXX系列的?
详细解析
一、启动类注解
Spring Boot 应用的入口类需要通过注解声明启动逻辑,一个注解顶三个传统配置。
| 注解 | 作用 |
|---|---|
| @SpringBootApplication | 启动类核心注解,是以下三个注解的组合(约定优于配置的入口): 1. @SpringBootConfiguration:声明当前类是配置类(等价于 @Configuration);2. @EnableAutoConfiguration:开启自动配置(让 Spring Boot 自动加载符合条件的 Bean);3. @ComponentScan:默认扫描当前包及子包下的 @Component 及其衍生注解(如 @Service)标记的类,注册为 Bean。 |
面试点小结
- 高频问题:如果不想让某些包被扫描,或者想自定义扫描路径,怎么做?—— 使用
@SpringBootApplication(scanBasePackages = "...")或者在@ComponentScan中单独配置。
代码示例:自定义扫描包路径
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
// 方式一:直接在 @SpringBootApplication 上指定扫描包
@SpringBootApplication(scanBasePackages = {
"com.example.service",
"com.example.web"
})
public class CustomScanApplication {
public static void main(String[] args) {
SpringApplication.run(CustomScanApplication.class, args);
}
}
// 方式二:配合 @ComponentScan 单独配置(等价写法)
@SpringBootApplication
@ComponentScan(basePackages = {
"com.example.service",
"com.example.web"
})
class AnotherApplication {
}代码示例:启动类写法
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}二、依赖注入(IOC)注解
Spring 的核心是 IOC(控制反转),常见问题就是:谁是 Bean?Bean 如何注入?注入冲突时怎么解决?
1. 声明 Bean 的注解(标记类/方法为可被 IOC 管理的组件)
| 注解 | 作用 |
|---|---|
| @Component | 通用组件标记(所有被 IOC 管理的类的基础注解)。 |
| @Service | 标记业务层(Service 层)组件(等价于@Component,语义更明确)。 |
| @Controller | 标记 Web 控制器组件(等价于@Component,语义更明确)。 |
| @Repository | 标记数据访问层(DAO 层)组件(等价于@Component,语义更明确,Spring 会自动将特定数据访问异常转换为 Spring 统一异常层次)。 |
| @Configuration | 标记配置类(通常用于声明@Bean方法),等价于传统 Spring 的 XML 配置文件。 |
| @Bean | 声明一个 Bean(标注在方法上,方法返回值会被注册到 IOC 容器)。 |
代码示例:分层组件与配置类
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Service
public class UserService {
public String getUserName() {
return "Tom";
}
}
@Repository
public class UserRepository {
// 模拟持久层
}
@Configuration
public class AppConfig {
@Bean
public String commonBean() {
return "I am a bean";
}
}易混点
@Component/@Service/@Controller/@Repository功能几乎相同,主要是语义和分层清晰,方便维护和 AOP 等按层次织入。@Configuration的类中方法如果标了@Bean,默认是单例且有 CGLIB 增强,同一个@Bean方法多次调用只会返回同一个 Bean。
这句话是什么意思?
- Spring 会为标注了
@Configuration的类创建一个 CGLIB 代理子类,拦截对@Bean方法的调用。 - 无论是在容器内部互相调用,还是你手动拿到配置类实例去调用
@Bean方法,最终都会从 IOC 容器中取同一个单例 Bean,而不是每次new一个。
什么是 CGLIB?
- CGLIB(Code Generation Library)是一个基于 字节码增强 的类库,可以在运行时为某个类生成一个子类,并通过方法拦截实现 AOP、代理等功能。
- 和基于 JDK 的动态代理只支持接口不同,CGLIB 可以代理没有实现接口的普通类,这也是 Spring 能够增强
@Configuration类、普通 Bean 类的关键手段之一。
代码示例:@Configuration + @Bean 的单例与代理行为
@Configuration
public class BeanConfig {
@Bean
public User user() {
return new User();
}
@Bean
public List<User> userList() {
// 虽然看起来调用了两次 user(),但因为有 CGLIB 代理,这里返回的是同一个单例 Bean
return Arrays.asList(user(), user());
}
}扩展:如果这里的类不是
@Configuration而只是@Component,那么user()方法不会被代理拦截,每次调用都会new一个对象,userList中就会有两个不同的 User 实例。
2. 注入 Bean 的注解(从 IOC 容器中获取 Bean)
| 注解 | 作用 |
|---|---|
| @Autowired | Spring 原生注入注解(默认按类型注入,可配合 @Qualifier 按名称指定,支持构造器/Setter/字段注入)。 |
| @Resource | JSR-250 标准注解(默认按名称注入,无名称时按类型注入,来自 jakarta.annotation / javax.annotation)。 |
| @Qualifier | 配合@Autowired使用,指定注入的 Bean 名称(解决同类型多 Bean 的歧义问题)。 |
| @Primary | 标记同类型 Bean 中的“主选” Bean(当@Autowired遇到多 Bean 时优先选择它)。 |
| @Lazy | 标记 Bean 为延迟加载(默认 IOC 启动时创建 Bean,@Lazy会在首次使用时创建)。 |
| @Scope | 指定 Bean 的作用域(如 singleton(默认单例)、prototype(多例)、request(HTTP 请求作用域)等)。 |
面试高频:@Autowired vs @Resource
- 来源不同:
@Autowired来自 Spring,@Resource来自 JSR 规范(更标准化)。 - 装配策略不同:
@Autowired先按类型匹配,再结合@Qualifier;@Resource默认按名称,找不到再按类型。 - 推荐实践:实际开发中更常见的是
@Autowired+ 构造器注入(更利于单元测试、不可变设计)。
代码示例:@Autowired、@Qualifier、@Primary
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
public interface MessageService {
String send();
}
@Component("emailService")
@Primary // 同类型多个 Bean 时,优先注入
class EmailService implements MessageService {
@Override
public String send() {
return "send email";
}
}
@Component("smsService")
class SmsService implements MessageService {
@Override
public String send() {
return "send sms";
}
}
@Component
class MessageController {
// 指定注入 smsService,而不是默认的 @Primary emailService
@Autowired
@Qualifier("smsService")
private MessageService messageService;
}三、配置管理注解
Spring Boot 通过 application.properties / application.yml 管理配置,常见问题是:简单配置用什么?复杂配置用什么?如何支持类型安全?
| 注解 | 作用 |
|---|---|
| @Value | 读取单个配置属性(支持 SpEL 表达式),如 @Value("${server.port}"),适合零散简单配置。 |
| @ConfigurationProperties | 批量绑定配置到 Java 对象(适用于复杂配置,如 prefix="spring.datasource" 绑定一组属性,支持 JSR303 校验)。 |
| @PropertySource | 加载自定义配置文件(默认加载 application.properties,可用此注解加载其他文件,如 @PropertySource("classpath:my-config.properties"))。 |
| @EnableConfigurationProperties | 启用 @ConfigurationProperties 标记的类(通常配合 @Configuration 或在启动类上使用)。 |
面试高频:@ConfigurationProperties vs @Value
@Value:适合零散、简单、单个字段的配置读取,不支持批量映射和校验。@ConfigurationProperties:适合成组配置、需要类型安全和校验的场景,推荐用于中大型项目。
代码示例:@Value 与 @ConfigurationProperties 读取配置
// application.yml app: name: demo-app version: v1.0 server: port: 8081
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String version;
// getter / setter 省略
}
@Component
public class ConfigDemo {
// 读取单个配置
@Value("${server.port}")
private int serverPort;
}四、Web 开发注解
Spring Boot 内置 Spring MVC,以下注解用于处理 HTTP 请求、响应和参数,是Controller 层面试的重灾区。
1. 控制器与请求映射
| 注解 | 作用 |
|---|---|
| @RestController | RESTful 控制器(等价于 @Controller + @ResponseBody,返回数据直接序列化为 JSON/JSONP/XML 等)。 |
| @Controller | 传统 MVC 控制器(返回视图名或配合 @ResponseBody 返回数据)。 |
| @RequestMapping | 通用请求映射(可标记类或方法,指定 URL 路径、请求方法等,如 @RequestMapping("/user"))。 |
| @GetMapping | @RequestMapping(method = RequestMethod.GET) 的简写(处理 GET 请求)。 |
| @PostMapping | 处理 POST 请求(类似@GetMapping)。 |
| @PutMapping | 处理 PUT 请求。 |
| @DeleteMapping | 处理 DELETE 请求。 |
代码示例:@RestController 与请求映射
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public String getUser(@PathVariable Long id) {
return "user id = " + id;
}
@PostMapping
public User createUser(@RequestBody User user) {
// 简化处理:直接返回请求体
return user;
}
}易错点
@RestController已经包含@ResponseBody,不要再在方法上重复标注@ResponseBody。- 类上
@RequestMapping+ 方法上@GetMapping,最终路径是类路径 + 方法路径拼接。
2. 请求参数与响应
| 注解 | 作用 |
|---|---|
| @RequestBody | 将请求体(如 JSON)反序列化为 Java 对象(用于 POST/PUT 等带请求体的请求)。 |
| @RequestParam | 读取 URL 中的查询参数(如 @RequestParam("username") String name),可设置默认值、是否必填。 |
| @PathVariable | 读取 URL 路径中的占位符(如 @GetMapping("/user/{id}") 配合 @PathVariable("id") Long userId)。 |
| @ResponseBody | 将返回值序列化为 JSON/XML(通常配合@Controller使用,@RestController已内置此注解)。 |
| @ResponseStatus | 设置响应状态码(如@ResponseStatus(HttpStatus.CREATED)返回 201 状态码)。 |
| @CrossOrigin | 解决跨域问题(标记类或方法,指定允许的源、方法等,常与前后端分离一起使用)。 |
面试常问
@RequestBody和@RequestParam的区别?—— 一个读 请求体,一个读 查询参数/表单字段。@PathVariable和@RequestParam的典型使用场景?—— 资源 ID 通常用路径变量,筛选条件用查询参数。
代码示例:@RequestParam、@PathVariable、@CrossOrigin
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://localhost:3000")
public class DemoController {
// GET /hello?name=Tom
@GetMapping("/hello")
public String hello(@RequestParam String name) {
return "hello " + name;
}
// GET /order/100
@GetMapping("/order/{id}")
public String getOrder(@PathVariable("id") Long orderId) {
return "order id = " + orderId;
}
}五、条件装配注解(自动配置核心)
Spring Boot 的自动配置本质上就是:根据条件装配不同的 Bean,因此 @ConditionalOnXXX 是理解自动配置的关键。
| 注解 | 作用 |
|---|---|
| @Conditional | 通用条件装配(需自定义 Condition 接口实现,很少直接在业务代码中使用,多见于基础框架)。 |
| @ConditionalOnClass | 当类路径中存在指定类时,才加载当前 Bean(如 @ConditionalOnClass(DataSource.class))。 |
| @ConditionalOnMissingClass | 当类路径中不存在指定类时,才加载当前 Bean。 |
| @ConditionalOnBean | 当 IOC 容器中存在指定 Bean 时,才加载当前 Bean。 |
| @ConditionalOnMissingBean | 当 IOC 容器中不存在指定 Bean 时,才加载当前 Bean(用于提供默认实现,典型场景:允许用户自定义覆盖)。 |
| @ConditionalOnProperty | 当配置文件中存在指定属性且值符合条件时,才加载当前 Bean(如 @ConditionalOnProperty(prefix="redis", name="enable", havingValue="true"))。 |
| @ConditionalOnResource | 当类路径中存在指定资源(如文件)时,才加载当前 Bean。 |
代码示例:@ConditionalOnProperty 控制功能开关
// application.yml
feature:
sms:
enabled: trueimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
@Component
@ConditionalOnProperty(prefix = "feature.sms", name = "enabled", havingValue = "true")
public class SmsSender {
// 只有当 feature.sms.enabled = true 时才会装配
}理解自动配置的一句话:自动配置 = 一堆 @Configuration 类 + 各种 @ConditionalOnXXX 条件判断 + SpringFactoriesLoader 加载机制。
六、功能启用注解(@Enable 系列)
以下注解用于开启 Spring Boot 的扩展功能,本质上是导入对应配置类,再配合条件装配完成 Bean 注册。
| 注解 | 作用 |
|---|---|
| @EnableAutoConfiguration | 开启自动配置(@SpringBootApplication已包含此注解)。 |
| @EnableScheduling | 开启任务调度(支持@Scheduled注解)。 |
| @EnableAsync | 开启异步方法支持(配合@Async使用)。 |
| @EnableCaching | 开启缓存支持(配合@Cacheable、@CachePut等注解)。 |
| @EnableTransactionManagement | 开启声明式事务支持(配合@Transactional使用)。 |
| @EnableFeignClients | 开启 Feign 客户端(用于微服务远程调用)。 |
代码示例:@EnableScheduling + @Scheduled 定时任务
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@SpringBootApplication
@EnableScheduling
public class ScheduleApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduleApplication.class, args);
}
}
@Component
class TaskJob {
// 每 5 秒执行一次
@Scheduled(fixedRate = 5000)
public void run() {
System.out.println("task running...");
}
}七、其他常用注解
| 注解 | 作用 |
|---|---|
| @Transactional | 声明事务(标记方法或类,支持事务隔离级别、传播行为等配置,是 Spring 事务的核心入口)。 |
| @Valid/@Validated | 开启参数校验(配合 jakarta.validation 约束注解,如 @NotBlank、@Max)。 |
| @Profile | 标记 Bean 仅在指定环境(如 dev、prod)中生效(通过 spring.profiles.active 配置激活)。 |
| @Import | 手动导入其他配置类或 Bean(类似 XML 中的 <import>,可实现简易模块组合)。 |
| @Aspect | 标记 AOP 切面类(配合 @Pointcut、@Before 等实现切面编程)。 |
常见面试点简要说明
@Transactional:- 默认只对 RuntimeException 及其子类 回滚,如需对受检异常回滚要显式配置
rollbackFor。 - 作用在接口/类/方法上,以方法级别优先;注意自调用导致事务失效的问题。
- 默认只对 RuntimeException 及其子类 回滚,如需对受检异常回滚要显式配置
@Profile:- 常与多数据源、多环境配置一起使用;可以用
@Profile("dev")标记开发环境专用 Bean。 - 生产环境通常通过 JVM 参数或配置中心设置
spring.profiles.active。
- 常与多数据源、多环境配置一起使用;可以用
代码示例:@Transactional 声明式事务
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
@Transactional(rollbackFor = Exception.class)
public void createOrder() {
// 1. 插入订单表
// 2. 扣减库存
// 3. 发生异常时整体回滚
}
}代码示例:@Valid 参数校验
// 引入依赖(通常在 pom.xml 中):
// spring-boot-starter-validation
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Max;
public class UserDTO {
@NotBlank(message = "用户名不能为空")
private String name;
@Max(value = 120, message = "年龄不能超过 120")
private int age;
// getter / setter 省略
}import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ValidateController {
@PostMapping("/users")
public String create(@Valid @RequestBody UserDTO user) {
return "ok";
}
}到此这篇关于SpringBoot 常用注解的文章就介绍到这了,更多相关springboot 常用注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
