Spring Boot 注解实战清单,别再死记硬背了

上周接了个电话面试,对面第一句就问:"Spring Boot 常用注解你平时怎么用的?"我当时脑子一抽,从 @Controller 开始背,背到 @Transactional 的时候对面已经沉默了。后来复盘才发现,注解这东西根本不该背,得按场景记。

我把平时项目里真正常用的注解整理了一下,按功能分了五类。每个注解都带实际代码,看完能直接用到项目里。

一、启动和配置类注解:项目跑起来的第一步

每个 Spring Boot 项目都有一个启动类,上面顶着那个经典的 @SpringBootApplication。这个注解其实是个三合一的组合:

java 复制代码
@SpringBootApplication // 组合注解,包含下面三个功能
public class DemoApplication {
    public static void main(String[] args) {
        // SpringApplication.run 启动内嵌 Tomcat,加载自动配置
        SpringApplication.run(DemoApplication.class, args);
    }
}

它等价于 @Configuration + @EnableAutoConfiguration + @ComponentScan 三个注解叠在一起。大多数时候你不需要拆开写,除非有特殊需求。

比如你想排除某个包不被扫描,就得拆开用了:

java 复制代码
@Configuration
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) // 排除数据源自动配置,用自定义的
@ComponentScan(basePackages = {"com.example.service", "com.example.controller"}) // 只扫描指定包
public class CustomConfig {
}

@Configuration 标记的类会被当作配置源,里面用 @Bean 定义的对象会注册到容器:

java 复制代码
@Configuration
public class AppConfig {

    @Bean // 把方法返回值注册为 Spring Bean,名字默认是方法名
    public RestTemplate restTemplate() {
        return new RestTemplate(); // 实际创建了一个 RestTemplate 实例
    }

    @Bean(initMethod = "init", destroyMethod = "cleanup") // 指定生命周期回调
    public CacheManager cacheManager() {
        return new CacheManager(); // 容器启动时调 init(),关闭时调 cleanup()
    }
}

这里有个坑要注意:同一个配置类里,@Bean 方法之间互相调用不会创建多个实例,Spring 会做代理保证单例。

二、组件注册注解:四个兄弟别搞混

Spring 提供了四个语义不同的组件注解,底层都是 @Component 的特化:

java 复制代码
@Component  // 通用组件,没有明确语义,万能兜底
@Service    // 业务逻辑层,标注在 Service 类上
@Repository // 数据访问层,标注在 DAO/Mapper 类上,额外提供数据库异常翻译
@Controller // Web 控制层,标注在 MVC 控制器上

实际项目中这样用:

java 复制代码
@Service
public class UserService {

    @Autowired // 按类型注入,容器里只有一个 UserMapper 时直接匹配
    private UserMapper userMapper;

    public User getUserById(Long id) {
        return userMapper.selectById(id); // 调用数据层查库
    }
}

@Repository
public class UserMapper {
    // MyBatis 或 JPA 的数据访问实现
}

@Autowired 默认按类型匹配。如果同类型有多个实现,配合 @Qualifier 指定名字:

java 复制代码
@Autowired
@Qualifier("smsSender") // 指定注入名为 smsSender 的实现
private MessageSender sender;

现在更推荐构造器注入,字段注入在测试时不好 mock:

java 复制代码
@Service
public class OrderService {
    private final UserService userService;
    private final PayService payService;

    // 构造器注入,Spring 4.3+ 单构造器时可以省略 @Autowired
    public OrderService(UserService userService, PayService payService) {
        this.userService = userService;
        this.payService = payService;
    }
}

三、Web 请求注解:接口怎么接参数怎么绑

写 REST 接口最常用的组合是 @RestController + @RequestMapping@RestController 等于 @Controller + @ResponseBody,方法返回值直接序列化成 JSON。

java 复制代码
@RestController
@RequestMapping("/api/users") // 类级别的路径前缀
public class UserController {

    @GetMapping("/{id}") // GET 请求,路径参数用 {} 占位
    public User getUser(
            @PathVariable Long id,           // 从 URL 路径里取值,/api/users/123 → id=123
            @RequestParam(defaultValue = "true") boolean active // 查询参数,带默认值
    ) {
        return userService.getUserById(id);
    }

    @PostMapping // POST 请求,接收 JSON 请求体
    public User createUser(@RequestBody UserDTO dto) { // @RequestBody 把请求体 JSON 反序列化成对象
        return userService.create(dto);
    }

    @DeleteMapping("/{id}") // DELETE 请求
    public void deleteUser(@PathVariable Long id) {
        userService.delete(id);
    }
}

@RequestParam@PathVariable 的区别很多人搞不清。简单说:@PathVariable 取 URL 路径里的值,@RequestParam?key=value 里的值。

还有个容易忘的 @RequestHeader,用来取请求头:

java 复制代码
@GetMapping("/info")
public String getInfo(
        @RequestHeader("Authorization") String token, // 取请求头里的 Authorization
        @CookieValue("session_id") String sessionId   // 取 Cookie 里的 session_id
) {
    return "token: " + token + ", session: " + sessionId;
}

四、配置绑定注解:yml 里的值怎么到代码里

@Value 是最简单的取值方式,适合取单个配置项:

java 复制代码
@Component
public class SmsConfig {

    @Value("${sms.api-key}") // 从 application.yml 里读 sms.api-key 的值
    private String apiKey;

    @Value("${sms.retry-count:3}") // 冒号后面是默认值,配置没写就用 3
    private int retryCount;

    @Value("${app.name:默认应用}") // 中文默认值也没问题
    private String appName;
}

配置项一多,@Value 就散得到处都是。这时候用 @ConfigurationProperties 批量绑定更干净:

java 复制代码
@Component
@ConfigurationProperties(prefix = "sms") // 把 sms 开头的所有配置批量绑到这个类上
public class SmsProperties {
    private String apiKey;      // 对应 sms.api-key(注意驼峰转短横线)
    private int retryCount;     // 对应 sms.retry-count
    private List<String> channels; // 对应 sms.channels[0], sms.channels[1]...

    // 必须提供 getter/setter,否则绑定不上
    public String getApiKey() { return apiKey; }
    public void setApiKey(String apiKey) { this.apiKey = apiKey; }
    public int getRetryCount() { return retryCount; }
    public void setRetryCount(int retryCount) { this.retryCount = retryCount; }
    public List<String> getChannels() { return channels; }
    public void setChannels(List<String> channels) { this.channels = channels; }
}

对应的 yml 配置:

yaml 复制代码
sms:
  api-key: abc123
  retry-count: 5
  channels:
    - aliyun
    - tencent

两种方式对比:@Value 适合零散取一两个值,@ConfigurationProperties 适合一组相关配置。后者还支持类型校验,加上 @Validated 就能在启动时检查配置是否合法。

五、常用功能注解速查

下面这张表把前面提到的注解做了个分类汇总,方便你快速定位:

分类 注解 作用 常见位置
启动配置 @SpringBootApplication 启动类标记,开启自动配置和包扫描 主类
启动配置 @Configuration + @Bean 手动注册 Bean 到容器 配置类
组件注册 @Service / @Repository 标记业务层 / 数据访问层组件 类级别
依赖注入 @Autowired 按类型自动注入依赖 构造器 / 字段
配置绑定 @Value 注入单个配置值 字段 / 方法参数
配置绑定 @ConfigurationProperties 批量绑定配置前缀到 POJO 类级别
Web 请求 @GetMapping / @PostMapping 映射 GET / POST 请求 方法级别
参数绑定 @PathVariable / @RequestParam 绑定路径参数 / 查询参数 方法参数
参数绑定 @RequestBody 请求体 JSON 反序列化为对象 方法参数

还有几个日常高频用到但容易忽略的:

java 复制代码
@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @PostMapping
    public Order create(@RequestBody @Valid OrderDTO dto) { // @Valid 触发 JSR-303 参数校验
        return orderService.create(dto);
    }

    @GetMapping
    @Transactional(readOnly = true) // 只读事务,查询场景性能更好
    public List<Order> list(@RequestParam(required = false) String status) {
        return orderService.list(status);
    }

    @ExceptionHandler(IllegalArgumentException.class) // 捕获特定异常,返回友好错误
    public Map<String, String> handleBadReq(IllegalArgumentException e) {
        return Map.of("error", e.getMessage());
    }
}

@Valid 配合 DTO 上的 @NotBlank@Size 等校验注解一起用,能在 Controller 层直接拦截非法参数,不用手写一堆 if 判断。

最后

整理下来就几条经验:

  • 注解按场景分类记,别按字母表背。启动配置、组件注册、Web 请求、配置绑定,四个类就够了。
  • @Autowired 优先用构造器注入,方便测试也方便排查。
  • 配置少用 @Value,多了就上 @ConfigurationProperties,类型安全还能校验。
  • @RestController@Controller 的区别就是返回 JSON 还是返回视图,别搞混。
  • @PathVariable 取路径值,@RequestParam 取问号后面的值,记住这个就行。

你平时项目里还有哪些注解用得特别多?评论区聊聊,说不定下次面试就考到了。

相关推荐
声音收集者1 小时前
Docker 常用命令的 5 个坑,第四个我踩了两次
程序员
芝士土豆薯片1 小时前
CSS Grid 布局实战指南,看这篇就够了
程序员
嘟嘟嘟95274 小时前
Spotify Honk 的启示:AI 编程日常
人工智能·程序员·ai编程
程序员cxuan4 小时前
从 0 到 1 速通 WorkBuddy
人工智能·后端·程序员
野生的码农17 小时前
5 年级的儿子居然学会了破解。。。
程序员
这个DBA有点耶21 小时前
数据库教程:从零基础到实战的完整学习路径(2026版)
数据库·程序员·代码规范
kyriewen1 天前
GPT-6 拿下模型众测第一:我拆完 30 个主题的实时榜单,「最强 AI」得看你问哪个场景
人工智能·程序员·ai编程
Sam_Deep_Thinking1 天前
单一职责原则:JAVA LocalDate的设计取舍
java·后端·程序员·单一职责原则