目录
[① 导读卡片](#① 导读卡片)
[② 背景与目标](#② 背景与目标)
[③ 概念与原理](#③ 概念与原理)
[④ 逻辑与对比](#④ 逻辑与对比)
[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 ...
}
}
@ConfigurationPropertiesvs@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 如何判断类是否存在 |
互动:你见过最「骚操作」的注解用法是什么?或者面试中被哪个注解问倒了?评论区分享 📝