Spring Boot常用注解全解

目录

[① 导读卡片](#① 导读卡片)

[② 背景与目标](#② 背景与目标)

为什么需要这篇注解大全?

[③ 概念与原理](#③ 概念与原理)

注解分类全景

注解处理的底层原理

[④ 逻辑与对比](#④ 逻辑与对比)

注解查询速查表

[1. 组件注册](#1. 组件注册)

[2. 依赖注入](#2. 依赖注入)

[3. Web 层](#3. Web 层)

[4. 配置属性](#4. 配置属性)

[5. 条件与作用域](#5. 条件与作用域)

[6. AOP / 事务 / 异步](#6. AOP / 事务 / 异步)

[⑤ 核心详解](#⑤ 核心详解)

[1. @Component 家族详解(含 @Repository 专题)](#1. @Component 家族详解(含 @Repository 专题))

[@Repository 深度解析](#@Repository 深度解析)

[2. @Autowired + @Qualifier 详解](#2. @Autowired + @Qualifier 详解)

[3. @Value 注入配置](#3. @Value 注入配置)

[4. @ConfigurationProperties 批量绑定](#4. @ConfigurationProperties 批量绑定)

[5. @Transactional 详解](#5. @Transactional 详解)

[6. Web 层注解组合示例](#6. Web 层注解组合示例)

[⑥ 案例实战](#⑥ 案例实战)

[实战:一个完整的 RESTful 接口(注解全用上)](#实战:一个完整的 RESTful 接口(注解全用上))

[⑦ 避坑 & 最佳实践](#⑦ 避坑 & 最佳实践)

[❌ 常见坑点](#❌ 常见坑点)

[✅ 最佳实践速查](#✅ 最佳实践速查)

[⑧ 总结 & 路线图](#⑧ 总结 & 路线图)

记住了什么?

快速定位

下一步去哪?


① 导读卡片

项目 内容
一句话定位 一篇文章覆盖 Spring Boot 最常用的 30+ 个注解,按功能分类,看完你就能看懂 90% 的项目代码
适合人群 Java 初学者、Spring Boot 新手、需要快速查阅的开发者
难度 ⭐⭐(基础 · 可查阅)
阅读时长 15 分钟(通读) / 2 分钟(查阅)
前置知识 基本 Java 语法,了解 IoC 概念

② 背景与目标

为什么需要这篇注解大全?

Spring Boot 项目里,注解随处可见:

java 复制代码
@SpringBootApplication
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
    
    private final UserService userService;
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }
    
    @PostMapping
    public User createUser(@Valid @RequestBody CreateUserRequest request) {
        return userService.create(request);
    }
}

每个注解都有自己的作用。面试常问、开发常用、踩坑常见。

学完本文,你能够:

  • 知道每个常见注解的作用和用法

  • 遇到某个注解不会用时快速找到答案

  • 写代码时选对注解、用对位置


③ 概念与原理

注解分类全景

Spring Boot 的注解按功能可分为六大类:

复制代码

注解处理的底层原理

Spring 通过后置处理器(BeanPostProcessor) 处理注解:

复制代码
容器启动 → 扫描类/方法 → 发现注解 → 找到对应的处理器 → 执行逻辑
注解 处理器 处理时机
@Autowired AutowiredAnnotationBeanPostProcessor 属性注入阶段
@PostConstruct CommonAnnotationBeanPostProcessor 初始化前
@Transactional TransactionInterceptor 方法调用时(AOP)
@RequestMapping RequestMappingHandlerMapping 启动时注册路由
@Component ClassPathBeanDefinitionScanner 扫描阶段

④ 逻辑与对比

注解查询速查表

1. 组件注册
注解 标注位置 作用 使用场景
@Component 通用组件,注册为 Bean 工具类、通用组件
@Service 服务层组件(@Component 特化) 业务逻辑类
@Repository 数据访问层组件 DAO / Mapper 类
@Controller MVC 控制器(返回视图用) 传统 Spring MVC
@RestController RESTful 控制器(返回 JSON) 前后端分离接口
@Configuration 配置类,声明 @Bean 方法 配置类
@Bean 方法 注册方法返回值为 Bean 注册第三方类
2. 依赖注入
注解 标注位置 作用 使用场景
@Autowired 字段/构造器/方法 按类型注入 最常用的注入注解
@Qualifier 字段/参数 按名称指定注入 多个同类型 Bean 时
@Primary 设置首选 Bean 多个实现中的默认
@Resource 字段/方法 按名称注入(JSR-250) Java 原生方式
@Inject 字段/构造器/方法 同 @Autowired(JSR-330) 想换框架时用
@Value 字段/参数 注入配置属性值 注入配置文件值
3. Web 层
注解 标注位置 作用 使用场景
@RequestMapping 类/方法 映射 HTTP 请求路径 任意 HTTP 方法
@GetMapping 方法 映射 GET 请求 查询接口
@PostMapping 方法 映射 POST 请求 新增接口
@PutMapping 方法 映射 PUT 请求 更新接口
@DeleteMapping 方法 映射 DELETE 请求 删除接口
@PatchMapping 方法 映射 PATCH 请求 部分更新
@PathVariable 参数 获取 URL 路径参数 /users/{id}
@RequestParam 参数 获取查询参数 /users?page=1
@RequestBody 参数 获取请求体 JSON 接收 POST 参数
@RequestHeader 参数 获取请求头 获取 Token
@ResponseBody 类/方法 返回值直接写回响应 返回 JSON
@RestController = @Controller + @ResponseBody 推荐!
4. 配置属性
注解 标注位置 作用 使用场景
@ConfigurationProperties 绑定配置前缀到属性 批量读取配置
@EnableConfigurationProperties 启用 @ConfigurationProperties 配合使用
@PropertySource 指定外部配置文件 加载自定义 .properties
@Value 字段/参数 注入单个配置值 简单配置读取
5. 条件与作用域
注解 作用 使用场景
@Scope 设置 Bean 作用域 singleton / prototype / request
@Lazy 延迟加载 启动慢的 Bean
@Profile 环境区分 dev / test / prod
@ConditionalOnClass 类路径存在时生效 自动配置
@ConditionalOnMissingBean Bean 不存在时生效 自动配置兜底
@ConditionalOnProperty 配置属性满足时生效 功能开关
6. AOP / 事务 / 异步
注解 作用 使用场景
@Transactional 声明式事务管理 数据库操作
@Async 异步执行 非关键路径操作
@EnableAsync 开启异步支持 配置类
@Cacheable 方法结果缓存 缓存查询结果
@CacheEvict 清除缓存 更新/删除后
@EventListener 监听事件 解耦业务逻辑

⑤ 核心详解

1. @Component 家族详解(含 @Repository 专题)

@Component@Service@Repository@Controller 本质都是 @Component(通过元注解派生)。

java 复制代码
// 四个注解的「本质」是一样的
@Service    = @Component + 语义:服务层
@Repository = @Component + 语义:数据层 + 异常转换
@Controller = @Component + 语义:控制层
@Repository 深度解析

作用

  • 标注数据访问层(DAO 层)组件

  • 将类识别为 Bean 并注册到容器

  • 将数据访问异常封装为 Spring 的 DataAccessException(这是它独有的功能)

java 复制代码
@Repository
public class UserDao {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public User findById(Long id) {
        try {
            return jdbcTemplate.queryForObject(
                "SELECT * FROM users WHERE id = ?",
                new BeanPropertyRowMapper<>(User.class),
                id
            );
        } catch (DataAccessException e) {
            // @Repository 会自动将 SQLException 转换为 DataAccessException
            throw new DataAccessResourceFailureException("数据库访问失败", e);
        }
    }
}

与 @Mapper 的区别

对比项 @Repository @Mapper
所属框架 Spring MyBatis
作用 注册 Bean + 异常转换 MyBatis 映射接口标记
标注对象 类 / 接口 接口
核心能力 Spring 容器管理 MyBatis 代理生成
能否单独使用 需配合扫描配置 可直接使用

@Repository 的最佳实践

java 复制代码
// ✅ 推荐:结合 @MapperScan(Spring Boot 项目)
@SpringBootApplication
@MapperScan("com.example.mapper")  // 扫描 Mapper 接口
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
​
// Mapper 接口不需要 @Repository,@MapperScan 会处理
public interface UserMapper {
    User selectById(Long id);
}
​
// 如果想消除 IDE 警告,可以加 @Repository
@Repository  // 只是消除警告,不影响功能
public interface UserMapper {
    User selectById(Long id);
}

2. @Autowired + @Qualifier 详解

java 复制代码
public interface PaymentService {
    void pay(BigDecimal amount);
}
​
@Component
@Primary  // 默认优先使用
public class AlipayService implements PaymentService { ... }
​
@Component("wechatPayService")
public class WechatPayService implements PaymentService { ... }
​
// 使用场景
@Component
public class PaymentClient {
    
    // 方式1:默认注入(有 @Primary 的 AlipayService)
    @Autowired
    private PaymentService paymentService;
    
    // 方式2:用 @Qualifier 指定
    @Autowired
    @Qualifier("wechatPayService")
    private PaymentService wechatPay;
    
    // 方式3:注入所有实现
    @Autowired
    private List<PaymentService> allServices;
    
    // 方式4:注入 Map(key = Bean 名称)
    @Autowired
    private Map<String, PaymentService> serviceMap;
}

3. @Value 注入配置

java 复制代码
# application.yml
app:
  name: 我的应用
  version: 2.0.0
  timeout: 5000
  features:
    - email
    - sms
@Component
public class AppProperties {
    
    @Value("${app.name}")
    private String appName;
    
    @Value("${app.version:1.0.0}")  // 默认值
    private String version;
    
    @Value("${app.timeout}")
    private int timeout;
    
    // SpEL 表达式
    @Value("#{${app.timeout} * 2}")
    private int doubleTimeout;
    
    // 环境变量
    @Value("${JAVA_HOME}")
    private String javaHome;
}

4. @ConfigurationProperties 批量绑定

java 复制代码
# application.yml
myapp:
  datasource:
    url: jdbc:mysql://localhost:3306/db
    username: root
    password: 123456
    pool:
      max-size: 20
      min-idle: 5
@Component
@ConfigurationProperties(prefix = "myapp.datasource")
public class DataSourceProperties {
    private String url;
    private String username;
    private String password;
    private Pool pool = new Pool();  // 嵌套类
    
    // getter / setter ...
    
    public static class Pool {
        private int maxSize;
        private int minIdle;
        // getter / setter ...
    }
}

@ConfigurationProperties vs @Value:批量配置项用 @ConfigurationProperties,单值用 @Value


5. @Transactional 详解

java 复制代码
@Service
public class UserService {
    
    // 默认只回滚 RuntimeException 和 Error
    @Transactional
    public void createUser(User user) {
        userDao.insert(user);
        
        // 发生 RuntimeException → 自动回滚
        // 需要检查异常也回滚:@Transactional(rollbackFor = Exception.class)
    }
    
    // 指定事务管理器 + 只读优化
    @Transactional(readOnly = true)
    public User findById(Long id) {
        return userDao.findById(id);
    }
    
    // 传播行为
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logAudit(AuditLog log) {
        // 独立事务,不受外层事务影响
        auditDao.insert(log);
    }
}

6. Web 层注解组合示例

java 复制代码
@RestController  // = @Controller + @ResponseBody
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
    
    private final UserService userService;
    
    @GetMapping
    public Result<List<User>> list(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {
        return Result.success(userService.findAll(page, size));
    }
    
    @GetMapping("/{id}")
    public Result<User> getById(@PathVariable Long id) {
        return Result.success(userService.findById(id));
    }
    
    @PostMapping
    public Result<User> create(@Valid @RequestBody CreateUserRequest request) {
        return Result.success(userService.create(request));
    }
    
    @PutMapping("/{id}")
    public Result<User> update(
            @PathVariable Long id,
            @Valid @RequestBody UpdateUserRequest request) {
        return Result.success(userService.update(id, request));
    }
    
    @DeleteMapping("/{id}")
    public Result<Void> delete(@PathVariable Long id) {
        userService.delete(id);
        return Result.success();
    }
}

⑥ 案例实战

实战:一个完整的 RESTful 接口(注解全用上)

java 复制代码
// 1. 配置属性
@ConfigurationProperties(prefix = "app.features")
@Component
@Data
public class FeatureConfig {
    private boolean emailEnabled;
    private int maxUploadSize;
}

// 2. 实体 + Repository
@Data
@Entity
@Table(name = "articles")
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String content;
    @Column(name = "created_at")
    private LocalDateTime createdAt;
}

@Repository
public interface ArticleRepository extends JpaRepository<Article, Long> {
    List<Article> findByTitleContaining(String keyword);
}

// 3. Service 层
@Service
@Transactional
@RequiredArgsConstructor
public class ArticleService {
    
    private final ArticleRepository repository;
    private final FeatureConfig featureConfig;
    
    @Cacheable("articles")
    public List<Article> findAll() {
        return repository.findAll();
    }
    
    @CacheEvict(value = "articles", allEntries = true)
    public Article create(Article article) {
        article.setCreatedAt(LocalDateTime.now());
        return repository.save(article);
    }
    
    @Async
    @EventListener
    public void handleArticleCreated(ArticleCreatedEvent event) {
        // 异步处理:发送通知、生成缓存等
        System.out.println("文章已创建: " + event.getArticleId());
    }
}

// 4. Controller 层
@RestController
@RequestMapping("/api/articles")
@RequiredArgsConstructor
public class ArticleController {
    
    private final ArticleService articleService;
    
    @GetMapping
    public Result<List<Article>> list(
            @RequestParam(required = false) String keyword) {
        return Result.success(articleService.findAll());
    }
    
    @PostMapping
    public Result<Article> create(
            @Valid @RequestBody CreateArticleRequest request) {
        Article article = new Article();
        BeanUtils.copyProperties(request, article);
        return Result.success(articleService.create(article));
    }
    
    @GetMapping("/{id}")
    public Result<Article> getById(@PathVariable Long id) {
        return Result.success(articleService.findById(id));
    }
}

⑦ 避坑 & 最佳实践

❌ 常见坑点

坑 1:@Transactional 不生效

java 复制代码
// ❌ 不生效------同一个类中方法调用
@Service
public class UserService {
    @Transactional
    public void methodA() {
        methodB(); // 直接调用,不走代理!
    }
    
    @Transactional
    public void methodB() { }
}

// ✅ 正确做法:注入自身代理
@Service
public class UserService {
    @Autowired
    private UserService self;
    
    @Transactional
    public void methodA() {
        self.methodB(); // 通过代理调用
    }
}

坑 2:@Value 注入失败

java 复制代码
# application.yml 中漏了配置
app.name: 我的应用
@Value("${app.name}")
private String name; // ✅ 配置存在

@Value("${app.nonexistent}")
private String value; // ❌ 启动报错!MissingPropertyException

// ✅ 加默认值
@Value("${app.nonexistent:default}")
private String value; // 启动成功,值为 "default"

坑 3:@Autowired private 字段单元测试难

java 复制代码
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository; // private,测试里不能直接赋值
}
✅ 改用构造器注入。

坑 4:@Repository + @Mapper 重复代理

java 复制代码
@Repository
public interface UserMapper { // ⚠️ 如果同时用了 @MapperScan
    // MyBatis 生成代理后,Spring 又生成一次代理 → 可能出问题
}
✅ 建议只用 @MapperScan,或只在接口上保留 @Mapper。

✅ 最佳实践速查

场景 推荐用法
组件注册 业务类用 @Service,不要在接口上加
依赖注入 构造器注入,配合 @RequiredArgsConstructor
Web 接口 @RestController + 方法级 @XxxMapping
配置读取 批量用 @ConfigurationProperties,单个用 @Value
事务控制 @Transactional + rollbackFor = Exception.class
异步任务 @Async + @EnableAsync
条件 Bean @ConditionalOnProperty 做功能开关
排除注解 不需要的功能用 exclude 关闭

⑧ 总结 & 路线图

记住了什么?

复制代码
六大类 + 一条主线:

组件注册:@Component 家族 → 谁管容器
依赖注入:@Autowired → 怎么装配
Web 层:@RestController 家族 → 怎么暴露接口
配置属性:@Value / @ConfigurationProperties → 怎么读配置
条件控制:@Conditional / @Profile → 什么时候生效
AOP/事务:@Transactional / @Async → 额外能力

快速定位

复制代码
想要注册 Bean             → @Component / @Service / @Bean
想要注入依赖              → @Autowired + 构造器注入
想要写 RESTful 接口       → @RestController + @XxxMapping
想要读取配置              → @Value / @ConfigurationProperties
想要事务控制              → @Transactional
想要异步执行              → @Async
想要条件判断              → @ConditionalOnXxx / @Profile
想要缓存                  → @Cacheable / @CacheEvict

下一步去哪?

学习方向 推荐内容
注解源码 选一个注解(如 @Transactional)看它的注解处理器源码
自定义注解 学习如何用 AOP 实现自定义注解
元注解机制 理解 @Component 如何派生出 @Service
条件注解底层 研究 @ConditionalOnClass 如何判断类是否存在

互动:你见过最「骚操作」的注解用法是什么?或者面试中被哪个注解问倒了?评论区分享 📝