Spring 注解开发指南
本文系统整理 Spring 框架中的核心注解,覆盖组件注册、依赖注入、Web MVC、Spring Boot、AOP、事务等常见场景,帮助开发者快速查阅和正确使用。
第一章 注解基础:元注解(Meta Annotations)
Java 注解(Annotation)是代码的元数据。Spring 大量使用注解替代 XML 配置。以下四个元注解用于定义其他注解:
| 元注解 | 作用 |
|---|---|
@Target | 指定该注解可以放在哪里(类、方法、字段等) |
@Retention | 指定注解保留到哪个阶段(源码、字节码、运行时) |
@Documented | 是否将注解包含在 Javadoc 中 |
@Inherited | 子类是否继承父类的该注解 |
@Target(ElementType.TYPE) // 只能用在类上
@Retention(RetentionPolicy.RUNTIME) // 运行时仍保留(反射可读)
public @interface MyAnnotation {
String value() default "";
}
Spring 的很多注解(如 @Component)本身就是被 @Target、@Retention 修饰过的,我们直接使用即可。
第二章 组件注册与依赖注入
2.1 声明 Bean:@Component 系列
Spring 管理的对象称为 Bean。将一个类交给 Spring 容器管理,最常用的方式是在类上添加以下注解之一:
| 注解 | 适用层 | 语义 |
|---|---|---|
@Component | 通用 | 通用的 Spring 组件 |
@Service | Service 层 | 业务逻辑层(语义更明确) |
@Repository | Dao 层 | 数据访问层(同时提供持久层异常转换) |
@Controller | Web 层 | 控制器层(配合 @RequestMapping 处理请求) |
@Service // 标注当前类是 Service 层的 Bean
public class UserService {
public String getUser() {
return "用户信息";
}
}
注意:这四个注解功能完全等价,Spring 都能扫描到。区分它们只是为了语义清晰,方便开发者快速理解类的职责。
2.2 依赖注入:@Autowired
@Autowired 由 Spring 提供,按类型(by type) 自动注入依赖。
@RestController
public class UserController {
@Autowired
private UserService userService; // Spring 自动注入 UserService 的实例
@GetMapping("/user")
public String getUser() {
return userService.getUser();
}
}
注入方式有三种:
@Service
public class UserServiceImpl implements UserService {
// 方式一:字段注入(最简洁,最常用)
@Autowired
private UserMapper userMapper;
// 方式二:Setter 注入
private RoleMapper roleMapper;
@Autowired
public void setRoleMapper(RoleMapper roleMapper) {
this.roleMapper = roleMapper;
}
// 方式三:构造器注入(Spring 官方推荐,便于测试和不可变设计)
private final LogMapper logMapper;
@Autowired // 如果类只有一个构造器,可以省略 @Autowired
public UserServiceImpl(LogMapper logMapper) {
this.logMapper = logMapper;
}
}
推荐:当依赖是必需的且在对象生命周期内不变时,优先使用构造器注入;字段注入最简洁但在单元测试中不易 mock。
@Autowired 的特殊配置:
@Autowired(required = false) // 找不到 Bean 时不报错(字段保持 null)
private MailService mailService;
2.3 按名称注入:@Qualifier
如果同一类型有多个 Bean,@Autowired 会因不知道注入哪个而报错。此时配合 @Qualifier 指定 Bean 名称:
@Component
public class SmsSender implements MessageSender { }
@Component("emailSender") // 自定义 Bean 名称
public class EmailSender implements MessageSender { }
@RestController
public class NotificationController {
@Autowired
@Qualifier("emailSender") // 指定注入名为 "emailSender" 的 Bean
private MessageSender messageSender;
}
2.4 @Primary:首选 Bean
当同一类型有多个 Bean 时,用 @Primary 标记其中一个为首选,@Autowired 默认注入它:
@Component
@Primary // 没有 @Qualifier 时默认注入这个
public class SmsSender implements MessageSender { }
2.5 @Resource(JSR-250):按名称注入
@Resource 是 Java 标准注解(非 Spring 专有),默认按名称(by name) 注入:
@Resource(name = "userService") // 按名称注入
private UserService userService;
// 不指定 name 时,以字段名作为查找名称
@Resource
private UserService userService; // 先按名称查找,找不到再按类型
2.6 Bean 作用域:@Scope
@Component
@Scope("singleton") // 单例(默认),整个容器只创建一个实例
// @Scope("prototype") // 原型,每次获取都创建新实例
// @Scope("request") // 每个 HTTP 请求创建一个(Web 容器中)
// @Scope("session") // 每个 HTTP Session 创建一个(Web 容器中)
public class UserService { }
2.7 延迟加载:@Lazy
@Component
@Lazy // 第一次使用时才创建,而不是容器启动时就创建
public class HeavyService { }
第三章 Spring Web MVC 注解
3.1 @RestController 与 @Controller
@RestController // = @Controller + @ResponseBody(所有方法返回值直接作为响应体)
public class UserController {
@GetMapping("/hello")
public String hello() {
return "Hello World"; // 直接返回字符串,不解析为视图
}
}
@Controller:标识一个类是 MVC 控制器,返回值通常解析为视图页面(JSP / Thymeleaf)。@RestController:是@Controller和@ResponseBody的组合注解。每个方法的返回值直接写入 HTTP 响应体(通常为 JSON),适合前后端分离的 API 开发。
@Controller // 传统 MVC:返回视图页面
public class PageController {
@GetMapping("/index")
public String index(Model model) {
model.addAttribute("name", "张三");
return "index"; // 解析为 index.html 模板
}
}
3.2 请求映射注解
| 注解 | 说明 |
|---|---|
@RequestMapping | 通用请求映射,可指定任意方法(GET、POST 等) |
@GetMapping | 简写 @RequestMapping(method = RequestMethod.GET) |
@PostMapping | 简写 @RequestMapping(method = RequestMethod.POST) |
@PutMapping | 简写 @RequestMapping(method = RequestMethod.PUT) |
@DeleteMapping | 简写 @RequestMapping(method = RequestMethod.DELETE) |
@PatchMapping | 简写 @RequestMapping(method = RequestMethod.PATCH) |
@RestController
@RequestMapping("/users") // 类级别:统一前缀
public class UserController {
@GetMapping("/{id}") // GET /users/1
public User get(@PathVariable Long id) { return ...; }
@PostMapping // POST /users
public User create(@RequestBody User user) { return ...; }
@PutMapping("/{id}") // PUT /users/1
public User update(@PathVariable Long id, @RequestBody User user) { return ...; }
@DeleteMapping("/{id}") // DELETE /users/1
public void delete(@PathVariable Long id) { ... }
}
3.3 参数绑定注解
| 注解 | 作用 |
|---|---|
@RequestParam | 绑定 URL 查询参数(?name=value) |
@RequestBody | 绑定请求体中的 JSON/XML 数据 |
@PathVariable | 绑定 URL 路径中的变量(/users/{id}) |
@RequestHeader | 绑定请求头 |
@CookieValue | 绑定 Cookie |
@ModelAttribute | 绑定表单数据到对象(常用于传统 MVC) |
@SessionAttribute | 绑定 Session 中的属性值 |
@RequestAttribute | 绑定 Request 作用域中的属性值 |
@RestController
public class DemoController {
// @RequestParam: 处理 ?page=1&size=10
@GetMapping("/list")
public String list(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
return "page=" + page + ", size=" + size;
}
// @PathVariable: 处理 /users/123
@GetMapping("/users/{id}")
public String getUser(@PathVariable Long id) {
return "userId=" + id;
}
// @RequestBody: 接收 JSON 请求体
@PostMapping("/users")
public String createUser(@RequestBody User user) {
return "created: " + user.getName();
}
// @RequestHeader: 获取请求头
@GetMapping("/info")
public String info(@RequestHeader("User-Agent") String userAgent) {
return "UA=" + userAgent;
}
// @SessionAttribute: 获取 Session 中的用户信息
@GetMapping("/profile")
public String profile(@SessionAttribute(value = "currentUser", required = false) User user) {
return user != null ? user.getName() : "未登录";
}
}
3.4 响应处理注解
@ResponseBody:将方法返回值直接写入 HTTP 响应体(Spring 自动将对象转为 JSON):
@Controller
public class UserController {
@GetMapping("/user")
@ResponseBody // 不加的话会去查找 user.html 视图
public User getUser() {
return new User("张三", 18);
}
}
@ResponseStatus:指定响应状态码:
@ResponseStatus(HttpStatus.CREATED) // 返回 201
@PostMapping("/users")
public User create(@RequestBody User user) { ... }
3.5 全局异常处理注解
@RestControllerAdvice // = @ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
public Result handleArithmetic(ArithmeticException e) {
return Result.error("数学运算异常:" + e.getMessage());
}
@ExceptionHandler(Exception.class) // 兜底处理
public Result handleException(Exception e) {
return Result.error("服务器内部错误");
}
}
| 注解 | 作用 |
|---|---|
@ControllerAdvice | 定义全局控制器增强(异常处理、数据绑定等) |
@RestControllerAdvice | @ControllerAdvice + @ResponseBody |
@ExceptionHandler | 处理指定类型的异常 |
第四章 Spring Boot 注解
注:关于@SpringBootApplication启动原理、条件装配注解 (@ConditionalXxx) 以及配置读取机制,已统一整理至 《Spring Boot 核心开发指南》。这里仅保留 Web 组件与生命周期相关注解。
4.1 @ServletComponentScan
在 Spring Boot 启动类上使用,扫描 @WebServlet、@WebFilter、@WebListener 注解:
@SpringBootApplication
@ServletComponentScan // 扫描 Filter、Servlet 等
public class Application { }
第五章 事务注解:@Transactional
本章侧重 @Transactional 注解速查。事务的 ACID、隔离级别、JDBC/MyBatis 协作、传播行为场景、失效排查等系统内容,请参阅 《Java 数据库事务实战》。
5.1 基本用法
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private LogMapper logMapper;
@Transactional // 该方法中的所有数据库操作在同一个事务中执行
public void transfer(Long fromId, Long toId, BigDecimal amount) {
userMapper.deduct(fromId, amount); // 扣钱
userMapper.add(toId, amount); // 加钱
logMapper.insert(new Log("转账成功")); // 记录日志
// 如果任意一步失败,所有操作回滚
}
}
5.2 常用属性
@Transactional(
propagation = Propagation.REQUIRED, // 事务传播行为(默认:有则加入,无则新建)
isolation = Isolation.READ_COMMITTED, // 事务隔离级别
timeout = 30, // 超时秒数
rollbackFor = Exception.class // 遇到哪些异常时回滚(默认只回滚 RuntimeException)
)
public void doSomething() { ... }
事务传播行为(propagation):
| 取值 | 说明 |
|---|---|
REQUIRED(默认) | 当前有事务则加入,没有则新建 |
REQUIRES_NEW | 不管有没有事务,都创建一个新事务 |
SUPPORTS | 有事务则加入,没有则以非事务方式执行 |
MANDATORY | 必须在已有事务中执行,否则抛异常 |
NEVER | 必须以非事务方式执行,有事务则抛异常 |
NOT_SUPPORTED | 以非事务方式执行,挂起当前事务 |
NESTED | 嵌套事务(JDBC 的 Savepoint 机制) |
注意:@Transactional默认只对RuntimeException(非受检异常)回滚,对受检异常(Exception 中的非 RuntimeException 子类)不会回滚。如需回滚所有异常,设置rollbackFor = Exception.class。
5.3 注意事项
@Transactional建议优先加在 public 方法上,这是最稳妥、最通用的写法。private方法稳定不会生效;在 Spring 6 / Boot 3 的类代理场景下,protected和包级可见方法不应一概而论,但实战中仍建议统一使用public方法声明事务边界。- 在同一个类中,方法 A(有事务)调用方法 B(有事务),B 的事务不会生效(Spring AOP 代理限制)。
- 正确用法:将事务方法放在不同的 Service 中调用,或通过
AopContext.currentProxy()自调用。
第六章 注解组合与最佳实践
6.1 Spring 的组合注解(Composed Annotations)
Spring 大量使用组合注解设计,即用一个注解封装多个注解的功能。
| 组合注解 | 包含的注解 |
|---|---|
@SpringBootApplication | @Configuration + @EnableAutoConfiguration + @ComponentScan |
@RestController | @Controller + @ResponseBody |
@GetMapping | @RequestMapping(method = GET) |
@RestControllerAdvice | @ControllerAdvice + @ResponseBody |
6.2 自定义组合注解
你可以像 Spring 一样,把常用的注解组合起来:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Controller
@ResponseBody
public @interface MyRestController {
@AliasFor(annotation = Controller.class, attribute = "value")
String value() default "";
}
6.3 常见误区与建议
| 误区 | 正确做法 |
|---|---|
在 private 方法上加 @Transactional | @Transactional 只在 public 方法上生效 |
在 Controller 层加 @Transactional | 事务应加在 Service 层的方法上 |
@Autowired 字段用 private | 可以,但字段注入在测试中不方便,优先构造器注入 |
所有 @Component 都使用 @Component | 按分层使用 @Service、@Repository、@Controller 语义更清晰 |
| 在循环依赖中使用字段注入解决 | 应重构代码消除循环依赖,而非依赖 @Lazy 绕过 |
总结
本文档整理了 Spring 开发中最常用的注解,从组件注册、Web 开发、自动配置到事务和 AOP。建议与以下文档配合阅读:
- Java Web 后端开发:三层架构、统一响应、JWT 与全局异常
- Java 数据库事务实战:传播行为、隔离级别与失效排查
- MyBatis 持久层开发:掌握数据库操作注解
@Results、@Select等 - MyBatis-Plus 单表开发与增强:了解 MP 对 MyBatis 的增强注解