Spring Boot注解全解:从入门到精通(面试避坑版)
本文系统梳理Spring Boot中最常用的注解,按照启动配置、Web层、IoC容器、AOP事务、属性绑定、条件注解六大分类逐一拆解。每个注解都配有作用说明、代码示例、实战避坑,帮助你彻底掌握Spring Boot注解体系。
一、注解为什么如此重要?
在Spring Boot中,注解是“约定大于配置”的核心体现。它们极大地简化了开发,把繁琐的XML配置变成了一行行简洁的元数据。
XML时代 vs 注解时代:
xml
<!-- XML时代:繁琐的配置 --> <bean id="userService" class="com.example.UserService"> <property name="userDao" ref="userDao"/> </bean> <bean id="userDao" class="com.example.UserDao"/>
java
// 注解时代:简洁优雅 @Service public class UserService { @Autowired private UserDao userDao; }核心思想:注解让开发者从“怎么配置”转向“做什么”,是Spring Boot快速开发的基础。
二、启动与配置类注解(门面担当)
2.1 @SpringBootApplication
Spring Boot应用的入口注解,标注在启动类上。
java
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }面试重点:@SpringBootApplication是组合注解,等价于:
| 注解 | 作用 |
|---|---|
@Configuration | 标识为配置类 |
@EnableAutoConfiguration | 开启自动配置 |
@ComponentScan | 扫描当前包及子包的Bean |
避坑:
@ComponentScan默认扫描启动类所在包及其子包。如果Bean在其他包中,需要通过@ComponentScan(basePackages = "com.example.other")手动指定。
2.2 @EnableAutoConfiguration
开启Spring Boot的自动配置功能。
原理:通过@Import(AutoConfigurationImportSelector.class)读取META-INF/spring.factories和META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,加载所有自动配置类。
面试金句:“自动配置的核心是
@EnableAutoConfiguration,它通过@Import导入选择器,读取spring.factories文件中的配置类,再配合@Conditional条件注解按需加载。”
2.3 @ComponentScan
扫描指定包下的@Component及其衍生注解(@Service、@Controller、@Repository等),将它们注册为Spring Bean。
java
@ComponentScan(basePackages = {"com.example.service", "com.example.dao"}) @SpringBootApplication public class Application { // ... }避坑:扫描不到Bean会抛出
NoSuchBeanDefinitionException。
三、Web层注解(Controller与参数绑定)
3.1 @RestController
标识一个类为RESTful控制器,所有方法默认返回JSON数据(不进行页面跳转)。
java
@RestController @RequestMapping("/user") public class UserController { @GetMapping("/{id}") public User getUser(@PathVariable Long id) { return userService.getById(id); } }本质:@RestController=@Controller+@ResponseBody
@Controller:标识控制器,默认返回视图(页面)@ResponseBody:方法返回值直接写入HTTP响应体(JSON/文本)
3.2 @RequestMapping / @GetMapping / @PostMapping
路由映射注解,将HTTP请求映射到处理方法。
java
@RestController @RequestMapping("/api/user") // 类上一级路径 public class UserController { @GetMapping("/{id}") // GET /api/user/1 public User get(@PathVariable Long id) { ... } @PostMapping // POST /api/user public User add(@RequestBody User user) { ... } @PutMapping("/{id}") // PUT /api/user/1 public User update(@PathVariable Long id, @RequestBody User user) { ... } @DeleteMapping("/{id}") // DELETE /api/user/1 public void delete(@PathVariable Long id) { ... } }| 注解 | 等价写法 |
|---|---|
@GetMapping | @RequestMapping(method = RequestMethod.GET) |
@PostMapping | @RequestMapping(method = RequestMethod.POST) |
@PutMapping | @RequestMapping(method = RequestMethod.PUT) |
@DeleteMapping | @RequestMapping(method = RequestMethod.DELETE) |
3.3 @RequestParam
接收URL查询字符串(Query String)中的参数。
text
GET /api/user?name=张三&age=25
java
@GetMapping("/user") public String getUser( @RequestParam String name, // 必传 @RequestParam(required = false) Integer age, // 可选 @RequestParam(defaultValue = "1") Integer page // 默认值 ) { return name + "," + age + "," + page; }避坑:不传
required=true的参数会报400错误,可用required=false或defaultValue解决。
3.4 @PathVariable
接收URL路径中的占位符。
text
GET /api/user/123
java
@GetMapping("/user/{id}") public User getUser(@PathVariable Long id) { return userService.getById(id); }避坑:必须加
@PathVariable注解才能将路径{id}映射到方法参数上。如果参数名和占位符名不一致,需指定@PathVariable("id")。
3.5 @RequestBody
接收HTTP请求体(Body)中的JSON/XML数据,自动反序列化为Java对象。
java
@PostMapping("/user") public User createUser(@RequestBody User user) { return userService.save(user); }⚠️ 致命陷阱:
@RequestBody只能用POST/PUT请求客户端必须设置
Content-Type: application/json如果传了JSON但不加
@RequestBody,Spring会尝试用字段名匹配Query String,导致解析失败
3.6 @RequestHeader
获取HTTP请求头中的值。
java
@GetMapping("/profile") public User getProfile(@RequestHeader("Authorization") String token) { // 常用于获取JWT Token return userService.getByToken(token); }四、IoC容器注解(Bean的注册与注入)
4.1 Bean注册注解(五大类注解)
| 注解 | 用途 | 本质 |
|---|---|---|
@Component | 通用组件,注册为Bean | 最基础的注解 |
@Service | 业务逻辑层(Service) | @Component的衍生 |
@Repository | 数据访问层(DAO) | @Component的衍生,额外转化JDBC异常 |
@Controller | 控制层(页面跳转) | @Component的衍生 |
@Configuration | 配置类(定义@Bean方法) | @Component的衍生,会被CGLIB代理 |
java
@Service public class UserService { ... } @Repository public class UserDao { ... } @Configuration public class AppConfig { @Bean public RedisTemplate redisTemplate() { ... } }面试金句:“
@Service、@Repository、@Controller、@Configuration本质上都是@Component,它们是Spring为不同分层提供的语义化注解。”
4.2 依赖注入注解
@Autowired
按类型(ByType)自动装配,Spring容器中匹配的Bean会被注入。
java
// 1. 字段注入(最简洁,但官方不推荐) @Service public class UserService { @Autowired private UserDao userDao; } // 2. 构造器注入(推荐:final修饰,不可变,便于单元测试) @Service public class UserService { private final UserDao userDao; @Autowired public UserService(UserDao userDao) { this.userDao = userDao; } } // 3. Setter注入(灵活性高,但可被修改) @Service public class UserService { private UserDao userDao; @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } }为什么推荐构造器注入?
| 优势 | 说明 |
|---|---|
| 不可变性 | 字段可以用final修饰,确保注入后不改变 |
| 单元测试友好 | 不需要Spring容器,直接用构造器传参即可测试 |
| 发现依赖问题早 | 构造时就能发现循环依赖等问题 |
| 语义清晰 | 强制明确依赖关系 |
@Qualifier
按名称(ByName)注入,配合@Autowired解决多个同类型Bean的冲突。
java
public interface MessageService { ... } @Service public class SmsService implements MessageService { ... } @Service public class EmailService implements MessageService { ... } @Service public class NotificationService { @Autowired @Qualifier("smsService") // 指定注入SmsService private MessageService messageService; }@Primary
当有多个同类型Bean时,标注首选注入的Bean。
java
@Primary @Service public class EmailService implements MessageService { ... }
@Qualifiervs@Primary:@Qualifier精准指定,@Primary设置默认(更隐式)。
@Autowired vs @Resource
| 维度 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring框架 | Java标准(JSR-250) |
| 注入方式 | 默认ByType | 默认ByName |
| 匹配失败 | 抛出异常 | 退化为ByType |
| 指定名称 | @Qualifier | name属性 |
4.3 @Bean
标注在方法上,将方法的返回值注册为Spring容器中的Bean。
java
@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); return template; } }使用场景:
整合第三方库(RedisTemplate、RestTemplate)
需要自定义Bean创建逻辑
无法在类上直接加
@Component(如第三方类)
避坑:
@Bean方法所在的类必须标注@Configuration,否则单例失效(@Configuration中的@Bean方法会被CGLIB代理,确保单例)。
五、AOP与事务注解
5.1 @Transactional
声明式事务,用AOP在方法执行前后自动开启、提交、回滚事务。
java
@Service public class OrderService { @Transactional public void createOrder(Order order) { // 1. 插入订单 // 2. 扣减库存 // 3. 扣减余额 // 任意一步失败,全部回滚 } }⚠️ 事务失效的5种场景(面试必问):
| 失效场景 | 原因 | 解决方案 |
|---|---|---|
| 方法不是public | 代理只对public方法生效 | 改为public |
| 同类自调用 | this.method()绕过代理对象 | 注入自身代理:@Autowired self; self.method() |
| 异常被catch吞掉 | 未抛异常,事务无法判断失败 | 重新抛出或在catch中手动回滚 |
| rollbackFor未指定 | 默认只回滚RuntimeException | 指定@Transactional(rollbackFor = Exception.class) |
| 数据库引擎不支持事务 | MyISAM引擎不支持事务 | 使用InnoDB引擎 |
事务传播行为(7种,重点记2种):
| 传播行为 | 含义 |
|---|---|
REQUIRED(默认) | 当前有事务就加入,没有就新建 |
REQUIRES_NEW | 总是新建事务,当前事务挂起 |
5.2 @Aspect
标识一个类为切面类,用于定义AOP横切逻辑(日志、权限、监控等)。
java
@Aspect @Component public class LogAspect { @Around("execution(* com.example.service.*.*(..))") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms"); return result; } }六、属性绑定注解
6.1 @Value
将application.properties/yml中的单个属性注入到字段中。
yaml
# application.yml server: port: 8080 aliyun: oss: endpoint: https://oss-cn-hangzhou.aliyuncs.com
java
@Component public class AppConfig { @Value("${server.port}") private int port; @Value("${aliyun.oss.endpoint}") private String ossEndpoint; }注意:
${}:取配置文件中的值#{}:Spring Expression Language(SpEL),如@Value("#{systemProperties['java.version']}")
6.2 @ConfigurationProperties
批量绑定配置文件中的一组属性到Java对象。
yaml
# application.yml aliyun: oss: endpoint: https://oss-cn-hangzhou.aliyuncs.com access-key-id: LTAI4G8xxx access-key-secret: xxxxxxx bucket-name: my-bucket
java
@Component @ConfigurationProperties(prefix = "aliyun.oss") @Data public class OssProperties { private String endpoint; private String accessKeyId; private String accessKeySecret; private String bucketName; }优势:省去一堆
@Value,自动映射,类型安全,IDE有自动补全。
6.3 @PropertySource
指定加载自定义配置文件(.properties文件)。
java
@Configuration @PropertySource("classpath:my-config.properties") public class MyConfig {